* [PATCH 01/15] md/raid1,raid10: clean up of RESYNC_SECTORS
2025-12-17 11:59 [PATCH 00/15] folio support for sync I/O in RAID linan666
@ 2025-12-17 11:59 ` linan666
2025-12-17 12:00 ` [PATCH 02/15] md: introduce sync_folio_io for folio support in RAID linan666
` (13 subsequent siblings)
14 siblings, 0 replies; 26+ messages in thread
From: linan666 @ 2025-12-17 11:59 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, xni, linan666, yangerkun, yi.zhang
From: Li Nan <linan122@huawei.com>
Move redundant RESYNC_SECTORS definition from raid1 and raid10
implementations to raid1-10.c.
Simplify max_sync assignment in raid10_sync_request().
No functional changes.
Signed-off-by: Li Nan <linan122@huawei.com>
---
drivers/md/raid1-10.c | 1 +
drivers/md/raid1.c | 1 -
drivers/md/raid10.c | 4 +---
3 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
index 521625756128..260d7fd7ccbe 100644
--- a/drivers/md/raid1-10.c
+++ b/drivers/md/raid1-10.c
@@ -2,6 +2,7 @@
/* 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)
/*
* Number of guaranteed raid bios in case of extreme VM load:
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 00120c86c443..407925951299 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -136,7 +136,6 @@ static void *r1bio_pool_alloc(gfp_t gfp_flags, struct r1conf *conf)
}
#define RESYNC_DEPTH 32
-#define RESYNC_SECTORS (RESYNC_BLOCK_SIZE >> 9)
#define RESYNC_WINDOW (RESYNC_BLOCK_SIZE * RESYNC_DEPTH)
#define RESYNC_WINDOW_SECTORS (RESYNC_WINDOW >> 9)
#define CLUSTER_RESYNC_WINDOW (16 * RESYNC_WINDOW)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 1adad768e277..1e57d9ce98e7 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -113,7 +113,6 @@ static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
return kzalloc(size, gfp_flags);
}
-#define RESYNC_SECTORS (RESYNC_BLOCK_SIZE >> 9)
/* amount of memory to reserve for resync requests */
#define RESYNC_WINDOW (1024*1024)
/* maximum number of concurrent requests, memory permitting */
@@ -3171,7 +3170,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
struct bio *biolist = NULL, *bio;
sector_t nr_sectors;
int i;
- int max_sync;
+ int max_sync = RESYNC_SECTORS;
sector_t sync_blocks;
sector_t chunk_mask = conf->geo.chunk_mask;
int page_idx = 0;
@@ -3284,7 +3283,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
* end_sync_write if we will want to write.
*/
- max_sync = RESYNC_PAGES << (PAGE_SHIFT-9);
if (!test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
/* recovery... the complicated one */
int j;
--
2.39.2
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH 02/15] md: introduce sync_folio_io for folio support in RAID
2025-12-17 11:59 [PATCH 00/15] folio support for sync I/O in RAID linan666
2025-12-17 11:59 ` [PATCH 01/15] md/raid1,raid10: clean up of RESYNC_SECTORS linan666
@ 2025-12-17 12:00 ` linan666
2025-12-17 12:00 ` [PATCH 03/15] md: use folio for bb_folio linan666
` (12 subsequent siblings)
14 siblings, 0 replies; 26+ messages in thread
From: linan666 @ 2025-12-17 12:00 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, xni, linan666, yangerkun, yi.zhang
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 cde84c9f05eb..9dfd6f8da5b8 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 [flat|nested] 26+ messages in thread* [PATCH 03/15] md: use folio for bb_folio
2025-12-17 11:59 [PATCH 00/15] folio support for sync I/O in RAID linan666
2025-12-17 11:59 ` [PATCH 01/15] md/raid1,raid10: clean up of RESYNC_SECTORS linan666
2025-12-17 12:00 ` [PATCH 02/15] md: introduce sync_folio_io for folio support in RAID linan666
@ 2025-12-17 12:00 ` linan666
2026-01-19 3:03 ` Xiao Ni
2025-12-17 12:00 ` [PATCH 04/15] md/raid1: use folio for tmppage linan666
` (11 subsequent siblings)
14 siblings, 1 reply; 26+ messages in thread
From: linan666 @ 2025-12-17 12:00 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, xni, linan666, yangerkun, yi.zhang
From: Li Nan <linan122@huawei.com>
Convert bio_page to bio_folio and use it throughout.
Signed-off-by: Li Nan <linan122@huawei.com>
---
drivers/md/md.h | 3 ++-
drivers/md/md.c | 25 +++++++++++++------------
2 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 410f8a6b75e7..aa6d9df50fd0 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -144,7 +144,8 @@ struct md_rdev {
struct block_device *bdev; /* block device handle */
struct file *bdev_file; /* Handle from open for bdev */
- struct page *sb_page, *bb_page;
+ struct page *sb_page;
+ struct folio *bb_folio;
int sb_loaded;
__u64 sb_events;
sector_t data_offset; /* start of data in array */
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 9dfd6f8da5b8..0732bbcdb95d 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1073,9 +1073,9 @@ void md_rdev_clear(struct md_rdev *rdev)
rdev->sb_start = 0;
rdev->sectors = 0;
}
- if (rdev->bb_page) {
- put_page(rdev->bb_page);
- rdev->bb_page = NULL;
+ if (rdev->bb_folio) {
+ folio_put(rdev->bb_folio);
+ rdev->bb_folio = NULL;
}
badblocks_exit(&rdev->badblocks);
}
@@ -1909,9 +1909,10 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
rdev->desc_nr = le32_to_cpu(sb->dev_number);
- if (!rdev->bb_page) {
- rdev->bb_page = alloc_page(GFP_KERNEL);
- if (!rdev->bb_page)
+ if (!rdev->bb_folio) {
+ rdev->bb_folio = folio_alloc(GFP_KERNEL, 0);
+
+ if (!rdev->bb_folio)
return -ENOMEM;
}
if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BAD_BLOCKS) &&
@@ -1930,10 +1931,10 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
if (offset == 0)
return -EINVAL;
bb_sector = (long long)offset;
- if (!sync_page_io(rdev, bb_sector, sectors << 9,
- rdev->bb_page, REQ_OP_READ, true))
+ if (!sync_folio_io(rdev, bb_sector, sectors << 9, 0,
+ rdev->bb_folio, REQ_OP_READ, true))
return -EIO;
- bbp = (__le64 *)page_address(rdev->bb_page);
+ bbp = (__le64 *)folio_address(rdev->bb_folio);
rdev->badblocks.shift = sb->bblog_shift;
for (i = 0 ; i < (sectors << (9-3)) ; i++, bbp++) {
u64 bb = le64_to_cpu(*bbp);
@@ -2300,7 +2301,7 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
md_error(mddev, rdev);
else {
struct badblocks *bb = &rdev->badblocks;
- __le64 *bbp = (__le64 *)page_address(rdev->bb_page);
+ __le64 *bbp = (__le64 *)folio_address(rdev->bb_folio);
u64 *p = bb->page;
sb->feature_map |= cpu_to_le32(MD_FEATURE_BAD_BLOCKS);
if (bb->changed) {
@@ -2953,7 +2954,7 @@ void md_update_sb(struct mddev *mddev, int force_change)
md_write_metadata(mddev, rdev,
rdev->badblocks.sector,
rdev->badblocks.size << 9,
- rdev->bb_page, 0);
+ folio_page(rdev->bb_folio, 0), 0);
rdev->badblocks.size = 0;
}
@@ -3809,7 +3810,7 @@ int md_rdev_init(struct md_rdev *rdev)
rdev->sb_events = 0;
rdev->last_read_error = 0;
rdev->sb_loaded = 0;
- rdev->bb_page = NULL;
+ rdev->bb_folio = NULL;
atomic_set(&rdev->nr_pending, 0);
atomic_set(&rdev->read_errors, 0);
atomic_set(&rdev->corrected_errors, 0);
--
2.39.2
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH 03/15] md: use folio for bb_folio
2025-12-17 12:00 ` [PATCH 03/15] md: use folio for bb_folio linan666
@ 2026-01-19 3:03 ` Xiao Ni
2026-01-20 11:49 ` Li Nan
0 siblings, 1 reply; 26+ messages in thread
From: Xiao Ni @ 2026-01-19 3:03 UTC (permalink / raw)
To: linan666; +Cc: song, yukuai, linux-raid, linux-kernel, yangerkun, yi.zhang
On Wed, Dec 17, 2025 at 8:11 PM <linan666@huaweicloud.com> wrote:
>
> From: Li Nan <linan122@huawei.com>
>
> Convert bio_page to bio_folio and use it throughout.
>
> Signed-off-by: Li Nan <linan122@huawei.com>
> ---
> drivers/md/md.h | 3 ++-
> drivers/md/md.c | 25 +++++++++++++------------
> 2 files changed, 15 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/md/md.h b/drivers/md/md.h
> index 410f8a6b75e7..aa6d9df50fd0 100644
> --- a/drivers/md/md.h
> +++ b/drivers/md/md.h
> @@ -144,7 +144,8 @@ struct md_rdev {
> struct block_device *bdev; /* block device handle */
> struct file *bdev_file; /* Handle from open for bdev */
>
> - struct page *sb_page, *bb_page;
> + struct page *sb_page;
> + struct folio *bb_folio;
> int sb_loaded;
> __u64 sb_events;
> sector_t data_offset; /* start of data in array */
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index 9dfd6f8da5b8..0732bbcdb95d 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -1073,9 +1073,9 @@ void md_rdev_clear(struct md_rdev *rdev)
> rdev->sb_start = 0;
> rdev->sectors = 0;
> }
> - if (rdev->bb_page) {
> - put_page(rdev->bb_page);
> - rdev->bb_page = NULL;
> + if (rdev->bb_folio) {
> + folio_put(rdev->bb_folio);
> + rdev->bb_folio = NULL;
> }
> badblocks_exit(&rdev->badblocks);
> }
> @@ -1909,9 +1909,10 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
>
> rdev->desc_nr = le32_to_cpu(sb->dev_number);
>
> - if (!rdev->bb_page) {
> - rdev->bb_page = alloc_page(GFP_KERNEL);
> - if (!rdev->bb_page)
> + if (!rdev->bb_folio) {
> + rdev->bb_folio = folio_alloc(GFP_KERNEL, 0);
> +
> + if (!rdev->bb_folio)
> return -ENOMEM;
> }
> if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BAD_BLOCKS) &&
> @@ -1930,10 +1931,10 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
> if (offset == 0)
> return -EINVAL;
> bb_sector = (long long)offset;
> - if (!sync_page_io(rdev, bb_sector, sectors << 9,
> - rdev->bb_page, REQ_OP_READ, true))
> + if (!sync_folio_io(rdev, bb_sector, sectors << 9, 0,
> + rdev->bb_folio, REQ_OP_READ, true))
> return -EIO;
> - bbp = (__le64 *)page_address(rdev->bb_page);
> + bbp = (__le64 *)folio_address(rdev->bb_folio);
> rdev->badblocks.shift = sb->bblog_shift;
> for (i = 0 ; i < (sectors << (9-3)) ; i++, bbp++) {
> u64 bb = le64_to_cpu(*bbp);
> @@ -2300,7 +2301,7 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
> md_error(mddev, rdev);
> else {
> struct badblocks *bb = &rdev->badblocks;
> - __le64 *bbp = (__le64 *)page_address(rdev->bb_page);
> + __le64 *bbp = (__le64 *)folio_address(rdev->bb_folio);
> u64 *p = bb->page;
> sb->feature_map |= cpu_to_le32(MD_FEATURE_BAD_BLOCKS);
> if (bb->changed) {
> @@ -2953,7 +2954,7 @@ void md_update_sb(struct mddev *mddev, int force_change)
> md_write_metadata(mddev, rdev,
> rdev->badblocks.sector,
> rdev->badblocks.size << 9,
> - rdev->bb_page, 0);
> + folio_page(rdev->bb_folio, 0), 0);
> rdev->badblocks.size = 0;
> }
>
> @@ -3809,7 +3810,7 @@ int md_rdev_init(struct md_rdev *rdev)
> rdev->sb_events = 0;
> rdev->last_read_error = 0;
> rdev->sb_loaded = 0;
> - rdev->bb_page = NULL;
> + rdev->bb_folio = NULL;
> atomic_set(&rdev->nr_pending, 0);
> atomic_set(&rdev->read_errors, 0);
> atomic_set(&rdev->corrected_errors, 0);
> --
> 2.39.2
>
Hi Nan
Bad block page is only one single page. I don't think it's necessary
to use folio here. And it uses folio_page to get the page again. Or do
you plan to replace all page apis to folio apis? Looking through all
patches, sync_page_io is not removed. In patch02, it says sync_page_io
will be removed. So maybe it's better to switch bb_page to bb_folio in
your second patch set? And this patch set only focuses on replacing
sync pages with folio. It's my 2 cents point. If you think it's better
to change the bad block page here, I'm still ok.
Best Regards
Xiao
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH 03/15] md: use folio for bb_folio
2026-01-19 3:03 ` Xiao Ni
@ 2026-01-20 11:49 ` Li Nan
0 siblings, 0 replies; 26+ messages in thread
From: Li Nan @ 2026-01-20 11:49 UTC (permalink / raw)
To: Xiao Ni, linan666
Cc: song, yukuai, linux-raid, linux-kernel, yangerkun, yi.zhang
在 2026/1/19 11:03, Xiao Ni 写道:
> On Wed, Dec 17, 2025 at 8:11 PM <linan666@huaweicloud.com> wrote:
>>
>> From: Li Nan <linan122@huawei.com>
>>
>> Convert bio_page to bio_folio and use it throughout.
>>
>> Signed-off-by: Li Nan <linan122@huawei.com>
>> ---
>> drivers/md/md.h | 3 ++-
>> drivers/md/md.c | 25 +++++++++++++------------
>> 2 files changed, 15 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/md/md.h b/drivers/md/md.h
>> index 410f8a6b75e7..aa6d9df50fd0 100644
>> --- a/drivers/md/md.h
>> +++ b/drivers/md/md.h
>> @@ -144,7 +144,8 @@ struct md_rdev {
>> struct block_device *bdev; /* block device handle */
>> struct file *bdev_file; /* Handle from open for bdev */
>>
>> - struct page *sb_page, *bb_page;
>> + struct page *sb_page;
>> + struct folio *bb_folio;
>> int sb_loaded;
>> __u64 sb_events;
>> sector_t data_offset; /* start of data in array */
>> diff --git a/drivers/md/md.c b/drivers/md/md.c
>> index 9dfd6f8da5b8..0732bbcdb95d 100644
>> --- a/drivers/md/md.c
>> +++ b/drivers/md/md.c
>> @@ -1073,9 +1073,9 @@ void md_rdev_clear(struct md_rdev *rdev)
>> rdev->sb_start = 0;
>> rdev->sectors = 0;
>> }
>> - if (rdev->bb_page) {
>> - put_page(rdev->bb_page);
>> - rdev->bb_page = NULL;
>> + if (rdev->bb_folio) {
>> + folio_put(rdev->bb_folio);
>> + rdev->bb_folio = NULL;
>> }
>> badblocks_exit(&rdev->badblocks);
>> }
>> @@ -1909,9 +1909,10 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
>>
>> rdev->desc_nr = le32_to_cpu(sb->dev_number);
>>
>> - if (!rdev->bb_page) {
>> - rdev->bb_page = alloc_page(GFP_KERNEL);
>> - if (!rdev->bb_page)
>> + if (!rdev->bb_folio) {
>> + rdev->bb_folio = folio_alloc(GFP_KERNEL, 0);
>> +
>> + if (!rdev->bb_folio)
>> return -ENOMEM;
>> }
>> if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BAD_BLOCKS) &&
>> @@ -1930,10 +1931,10 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
>> if (offset == 0)
>> return -EINVAL;
>> bb_sector = (long long)offset;
>> - if (!sync_page_io(rdev, bb_sector, sectors << 9,
>> - rdev->bb_page, REQ_OP_READ, true))
>> + if (!sync_folio_io(rdev, bb_sector, sectors << 9, 0,
>> + rdev->bb_folio, REQ_OP_READ, true))
>> return -EIO;
>> - bbp = (__le64 *)page_address(rdev->bb_page);
>> + bbp = (__le64 *)folio_address(rdev->bb_folio);
>> rdev->badblocks.shift = sb->bblog_shift;
>> for (i = 0 ; i < (sectors << (9-3)) ; i++, bbp++) {
>> u64 bb = le64_to_cpu(*bbp);
>> @@ -2300,7 +2301,7 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
>> md_error(mddev, rdev);
>> else {
>> struct badblocks *bb = &rdev->badblocks;
>> - __le64 *bbp = (__le64 *)page_address(rdev->bb_page);
>> + __le64 *bbp = (__le64 *)folio_address(rdev->bb_folio);
>> u64 *p = bb->page;
>> sb->feature_map |= cpu_to_le32(MD_FEATURE_BAD_BLOCKS);
>> if (bb->changed) {
>> @@ -2953,7 +2954,7 @@ void md_update_sb(struct mddev *mddev, int force_change)
>> md_write_metadata(mddev, rdev,
>> rdev->badblocks.sector,
>> rdev->badblocks.size << 9,
>> - rdev->bb_page, 0);
>> + folio_page(rdev->bb_folio, 0), 0);
>> rdev->badblocks.size = 0;
>> }
>>
>> @@ -3809,7 +3810,7 @@ int md_rdev_init(struct md_rdev *rdev)
>> rdev->sb_events = 0;
>> rdev->last_read_error = 0;
>> rdev->sb_loaded = 0;
>> - rdev->bb_page = NULL;
>> + rdev->bb_folio = NULL;
>> atomic_set(&rdev->nr_pending, 0);
>> atomic_set(&rdev->read_errors, 0);
>> atomic_set(&rdev->corrected_errors, 0);
>> --
>> 2.39.2
>>
>
> Hi Nan
>
> Bad block page is only one single page. I don't think it's necessary
> to use folio here. And it uses folio_page to get the page again. Or do
> you plan to replace all page apis to folio apis? Looking through all
> patches, sync_page_io is not removed. In patch02, it says sync_page_io
> will be removed. So maybe it's better to switch bb_page to bb_folio in
> your second patch set? And this patch set only focuses on replacing
> sync pages with folio. It's my 2 cents point. If you think it's better
> to change the bad block page here, I'm still ok.
>
> Best Regards
> Xiao
>
Hi Xiao,
Thanks for your review. Move it to next patch set is fine. I will delete
this patch in v2.
--
Thanks,
Nan
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH 04/15] md/raid1: use folio for tmppage
2025-12-17 11:59 [PATCH 00/15] folio support for sync I/O in RAID linan666
` (2 preceding siblings ...)
2025-12-17 12:00 ` [PATCH 03/15] md: use folio for bb_folio linan666
@ 2025-12-17 12:00 ` linan666
2026-01-19 3:20 ` Xiao Ni
2025-12-17 12:00 ` [PATCH 05/15] md/raid10: " linan666
` (10 subsequent siblings)
14 siblings, 1 reply; 26+ messages in thread
From: linan666 @ 2025-12-17 12:00 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, xni, linan666, yangerkun, yi.zhang
From: Li Nan <linan122@huawei.com>
Convert tmppage to tmpfolio and use it throughout in raid1.
Signed-off-by: Li Nan <linan122@huawei.com>
---
drivers/md/raid1.h | 2 +-
drivers/md/raid1.c | 18 ++++++++++--------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h
index c98d43a7ae99..d480b3a8c2c4 100644
--- a/drivers/md/raid1.h
+++ b/drivers/md/raid1.h
@@ -101,7 +101,7 @@ struct r1conf {
/* temporary buffer to synchronous IO when attempting to repair
* a read error.
*/
- struct page *tmppage;
+ struct folio *tmpfolio;
/* When taking over an array from a different personality, we store
* the new thread here until we fully activate the array.
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 407925951299..43453f1a04f4 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2417,8 +2417,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
rdev->recovery_offset >= sect + s)) &&
rdev_has_badblock(rdev, sect, s) == 0) {
atomic_inc(&rdev->nr_pending);
- if (sync_page_io(rdev, sect, s<<9,
- conf->tmppage, REQ_OP_READ, false))
+ if (sync_folio_io(rdev, sect, s<<9, 0,
+ conf->tmpfolio, REQ_OP_READ, false))
success = 1;
rdev_dec_pending(rdev, mddev);
if (success)
@@ -2447,7 +2447,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
!test_bit(Faulty, &rdev->flags)) {
atomic_inc(&rdev->nr_pending);
r1_sync_page_io(rdev, sect, s,
- conf->tmppage, REQ_OP_WRITE);
+ folio_page(conf->tmpfolio, 0),
+ REQ_OP_WRITE);
rdev_dec_pending(rdev, mddev);
}
}
@@ -2461,7 +2462,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
!test_bit(Faulty, &rdev->flags)) {
atomic_inc(&rdev->nr_pending);
if (r1_sync_page_io(rdev, sect, s,
- conf->tmppage, REQ_OP_READ)) {
+ folio_page(conf->tmpfolio, 0),
+ REQ_OP_READ)) {
atomic_add(s, &rdev->corrected_errors);
pr_info("md/raid1:%s: read error corrected (%d sectors at %llu on %pg)\n",
mdname(mddev), s,
@@ -3120,8 +3122,8 @@ static struct r1conf *setup_conf(struct mddev *mddev)
if (!conf->mirrors)
goto abort;
- conf->tmppage = alloc_page(GFP_KERNEL);
- if (!conf->tmppage)
+ conf->tmpfolio = folio_alloc(GFP_KERNEL, 0);
+ if (!conf->tmpfolio)
goto abort;
r1bio_size = offsetof(struct r1bio, bios[mddev->raid_disks * 2]);
@@ -3196,7 +3198,7 @@ static struct r1conf *setup_conf(struct mddev *mddev)
if (conf) {
mempool_destroy(conf->r1bio_pool);
kfree(conf->mirrors);
- safe_put_page(conf->tmppage);
+ folio_put(conf->tmpfolio);
kfree(conf->nr_pending);
kfree(conf->nr_waiting);
kfree(conf->nr_queued);
@@ -3310,7 +3312,7 @@ static void raid1_free(struct mddev *mddev, void *priv)
mempool_destroy(conf->r1bio_pool);
kfree(conf->mirrors);
- safe_put_page(conf->tmppage);
+ folio_put(conf->tmpfolio);
kfree(conf->nr_pending);
kfree(conf->nr_waiting);
kfree(conf->nr_queued);
--
2.39.2
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH 04/15] md/raid1: use folio for tmppage
2025-12-17 12:00 ` [PATCH 04/15] md/raid1: use folio for tmppage linan666
@ 2026-01-19 3:20 ` Xiao Ni
2026-01-20 3:38 ` Xiao Ni
0 siblings, 1 reply; 26+ messages in thread
From: Xiao Ni @ 2026-01-19 3:20 UTC (permalink / raw)
To: linan666; +Cc: song, yukuai, linux-raid, linux-kernel, yangerkun, yi.zhang
On Wed, Dec 17, 2025 at 8:11 PM <linan666@huaweicloud.com> wrote:
>
> From: Li Nan <linan122@huawei.com>
>
> Convert tmppage to tmpfolio and use it throughout in raid1.
>
> Signed-off-by: Li Nan <linan122@huawei.com>
> ---
> drivers/md/raid1.h | 2 +-
> drivers/md/raid1.c | 18 ++++++++++--------
> 2 files changed, 11 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h
> index c98d43a7ae99..d480b3a8c2c4 100644
> --- a/drivers/md/raid1.h
> +++ b/drivers/md/raid1.h
> @@ -101,7 +101,7 @@ struct r1conf {
> /* temporary buffer to synchronous IO when attempting to repair
> * a read error.
> */
> - struct page *tmppage;
> + struct folio *tmpfolio;
>
> /* When taking over an array from a different personality, we store
> * the new thread here until we fully activate the array.
> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> index 407925951299..43453f1a04f4 100644
> --- a/drivers/md/raid1.c
> +++ b/drivers/md/raid1.c
> @@ -2417,8 +2417,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
> rdev->recovery_offset >= sect + s)) &&
> rdev_has_badblock(rdev, sect, s) == 0) {
> atomic_inc(&rdev->nr_pending);
> - if (sync_page_io(rdev, sect, s<<9,
> - conf->tmppage, REQ_OP_READ, false))
> + if (sync_folio_io(rdev, sect, s<<9, 0,
> + conf->tmpfolio, REQ_OP_READ, false))
> success = 1;
> rdev_dec_pending(rdev, mddev);
> if (success)
> @@ -2447,7 +2447,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
> !test_bit(Faulty, &rdev->flags)) {
> atomic_inc(&rdev->nr_pending);
> r1_sync_page_io(rdev, sect, s,
> - conf->tmppage, REQ_OP_WRITE);
> + folio_page(conf->tmpfolio, 0),
> + REQ_OP_WRITE);
> rdev_dec_pending(rdev, mddev);
> }
> }
> @@ -2461,7 +2462,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
> !test_bit(Faulty, &rdev->flags)) {
> atomic_inc(&rdev->nr_pending);
> if (r1_sync_page_io(rdev, sect, s,
> - conf->tmppage, REQ_OP_READ)) {
> + folio_page(conf->tmpfolio, 0),
> + REQ_OP_READ)) {
> atomic_add(s, &rdev->corrected_errors);
> pr_info("md/raid1:%s: read error corrected (%d sectors at %llu on %pg)\n",
> mdname(mddev), s,
> @@ -3120,8 +3122,8 @@ static struct r1conf *setup_conf(struct mddev *mddev)
> if (!conf->mirrors)
> goto abort;
>
> - conf->tmppage = alloc_page(GFP_KERNEL);
> - if (!conf->tmppage)
> + conf->tmpfolio = folio_alloc(GFP_KERNEL, 0);
> + if (!conf->tmpfolio)
> goto abort;
>
> r1bio_size = offsetof(struct r1bio, bios[mddev->raid_disks * 2]);
> @@ -3196,7 +3198,7 @@ static struct r1conf *setup_conf(struct mddev *mddev)
> if (conf) {
> mempool_destroy(conf->r1bio_pool);
> kfree(conf->mirrors);
> - safe_put_page(conf->tmppage);
> + folio_put(conf->tmpfolio);
> kfree(conf->nr_pending);
> kfree(conf->nr_waiting);
> kfree(conf->nr_queued);
> @@ -3310,7 +3312,7 @@ static void raid1_free(struct mddev *mddev, void *priv)
>
> mempool_destroy(conf->r1bio_pool);
> kfree(conf->mirrors);
> - safe_put_page(conf->tmppage);
> + folio_put(conf->tmpfolio);
> kfree(conf->nr_pending);
> kfree(conf->nr_waiting);
> kfree(conf->nr_queued);
> --
> 2.39.2
>
Hi Nan
Same question for patch04 and patch05, tmpage is used in read io path.
From the cover letter, this patch set wants to resolve the multi pages
in sync io path. Is it better to keep them for your future patch set?
Best Regards
Xiao
Xiao
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH 04/15] md/raid1: use folio for tmppage
2026-01-19 3:20 ` Xiao Ni
@ 2026-01-20 3:38 ` Xiao Ni
2026-01-20 11:51 ` Li Nan
0 siblings, 1 reply; 26+ messages in thread
From: Xiao Ni @ 2026-01-20 3:38 UTC (permalink / raw)
To: linan666; +Cc: song, yukuai, linux-raid, linux-kernel, yangerkun, yi.zhang
在 2026/1/19 11:20, Xiao Ni 写道:
> On Wed, Dec 17, 2025 at 8:11 PM <linan666@huaweicloud.com> wrote:
>> From: Li Nan <linan122@huawei.com>
>>
>> Convert tmppage to tmpfolio and use it throughout in raid1.
>>
>> Signed-off-by: Li Nan <linan122@huawei.com>
>> ---
>> drivers/md/raid1.h | 2 +-
>> drivers/md/raid1.c | 18 ++++++++++--------
>> 2 files changed, 11 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h
>> index c98d43a7ae99..d480b3a8c2c4 100644
>> --- a/drivers/md/raid1.h
>> +++ b/drivers/md/raid1.h
>> @@ -101,7 +101,7 @@ struct r1conf {
>> /* temporary buffer to synchronous IO when attempting to repair
>> * a read error.
>> */
>> - struct page *tmppage;
>> + struct folio *tmpfolio;
>>
>> /* When taking over an array from a different personality, we store
>> * the new thread here until we fully activate the array.
>> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
>> index 407925951299..43453f1a04f4 100644
>> --- a/drivers/md/raid1.c
>> +++ b/drivers/md/raid1.c
>> @@ -2417,8 +2417,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
>> rdev->recovery_offset >= sect + s)) &&
>> rdev_has_badblock(rdev, sect, s) == 0) {
>> atomic_inc(&rdev->nr_pending);
>> - if (sync_page_io(rdev, sect, s<<9,
>> - conf->tmppage, REQ_OP_READ, false))
>> + if (sync_folio_io(rdev, sect, s<<9, 0,
>> + conf->tmpfolio, REQ_OP_READ, false))
>> success = 1;
>> rdev_dec_pending(rdev, mddev);
>> if (success)
>> @@ -2447,7 +2447,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
>> !test_bit(Faulty, &rdev->flags)) {
>> atomic_inc(&rdev->nr_pending);
>> r1_sync_page_io(rdev, sect, s,
>> - conf->tmppage, REQ_OP_WRITE);
>> + folio_page(conf->tmpfolio, 0),
>> + REQ_OP_WRITE);
>> rdev_dec_pending(rdev, mddev);
>> }
>> }
>> @@ -2461,7 +2462,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
>> !test_bit(Faulty, &rdev->flags)) {
>> atomic_inc(&rdev->nr_pending);
>> if (r1_sync_page_io(rdev, sect, s,
>> - conf->tmppage, REQ_OP_READ)) {
>> + folio_page(conf->tmpfolio, 0),
>> + REQ_OP_READ)) {
>> atomic_add(s, &rdev->corrected_errors);
>> pr_info("md/raid1:%s: read error corrected (%d sectors at %llu on %pg)\n",
>> mdname(mddev), s,
>> @@ -3120,8 +3122,8 @@ static struct r1conf *setup_conf(struct mddev *mddev)
>> if (!conf->mirrors)
>> goto abort;
>>
>> - conf->tmppage = alloc_page(GFP_KERNEL);
>> - if (!conf->tmppage)
>> + conf->tmpfolio = folio_alloc(GFP_KERNEL, 0);
>> + if (!conf->tmpfolio)
>> goto abort;
>>
>> r1bio_size = offsetof(struct r1bio, bios[mddev->raid_disks * 2]);
>> @@ -3196,7 +3198,7 @@ static struct r1conf *setup_conf(struct mddev *mddev)
>> if (conf) {
>> mempool_destroy(conf->r1bio_pool);
>> kfree(conf->mirrors);
>> - safe_put_page(conf->tmppage);
>> + folio_put(conf->tmpfolio);
>> kfree(conf->nr_pending);
>> kfree(conf->nr_waiting);
>> kfree(conf->nr_queued);
>> @@ -3310,7 +3312,7 @@ static void raid1_free(struct mddev *mddev, void *priv)
>>
>> mempool_destroy(conf->r1bio_pool);
>> kfree(conf->mirrors);
>> - safe_put_page(conf->tmppage);
>> + folio_put(conf->tmpfolio);
>> kfree(conf->nr_pending);
>> kfree(conf->nr_waiting);
>> kfree(conf->nr_queued);
>> --
>> 2.39.2
>>
> Hi Nan
>
> Same question for patch04 and patch05, tmpage is used in read io path.
> From the cover letter, this patch set wants to resolve the multi pages
> in sync io path. Is it better to keep them for your future patch set?
>
> Best Regards
> Xiao
>
> Xiao
After reading patch06, I understand here. r1_sync_page_io needs to
change to r1_sync_folio_io to handle sync read error. Please ignore my
above comments. patch04 and patch05 look good to me.
Best Regards
Xiao
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH 04/15] md/raid1: use folio for tmppage
2026-01-20 3:38 ` Xiao Ni
@ 2026-01-20 11:51 ` Li Nan
0 siblings, 0 replies; 26+ messages in thread
From: Li Nan @ 2026-01-20 11:51 UTC (permalink / raw)
To: Xiao Ni, linan666
Cc: song, yukuai, linux-raid, linux-kernel, yangerkun, yi.zhang
在 2026/1/20 11:38, Xiao Ni 写道:
>
> 在 2026/1/19 11:20, Xiao Ni 写道:
>> On Wed, Dec 17, 2025 at 8:11 PM <linan666@huaweicloud.com> wrote:
>>> From: Li Nan <linan122@huawei.com>
>>>
>>> Convert tmppage to tmpfolio and use it throughout in raid1.
>>>
>>> Signed-off-by: Li Nan <linan122@huawei.com>
>>> ---
>>> drivers/md/raid1.h | 2 +-
>>> drivers/md/raid1.c | 18 ++++++++++--------
>>> 2 files changed, 11 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h
>>> index c98d43a7ae99..d480b3a8c2c4 100644
>>> --- a/drivers/md/raid1.h
>>> +++ b/drivers/md/raid1.h
>>> @@ -101,7 +101,7 @@ struct r1conf {
>>> /* temporary buffer to synchronous IO when attempting to repair
>>> * a read error.
>>> */
>>> - struct page *tmppage;
>>> + struct folio *tmpfolio;
>>>
>>> /* When taking over an array from a different personality, we
>>> store
>>> * the new thread here until we fully activate the array.
>>> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
>>> index 407925951299..43453f1a04f4 100644
>>> --- a/drivers/md/raid1.c
>>> +++ b/drivers/md/raid1.c
>>> @@ -2417,8 +2417,8 @@ static void fix_read_error(struct r1conf *conf,
>>> struct r1bio *r1_bio)
>>> rdev->recovery_offset >= sect + s)) &&
>>> rdev_has_badblock(rdev, sect, s) == 0) {
>>> atomic_inc(&rdev->nr_pending);
>>> - if (sync_page_io(rdev, sect, s<<9,
>>> - conf->tmppage, REQ_OP_READ,
>>> false))
>>> + if (sync_folio_io(rdev, sect, s<<9, 0,
>>> + conf->tmpfolio, REQ_OP_READ,
>>> false))
>>> success = 1;
>>> rdev_dec_pending(rdev, mddev);
>>> if (success)
>>> @@ -2447,7 +2447,8 @@ static void fix_read_error(struct r1conf *conf,
>>> struct r1bio *r1_bio)
>>> !test_bit(Faulty, &rdev->flags)) {
>>> atomic_inc(&rdev->nr_pending);
>>> r1_sync_page_io(rdev, sect, s,
>>> - conf->tmppage,
>>> REQ_OP_WRITE);
>>> +
>>> folio_page(conf->tmpfolio, 0),
>>> + REQ_OP_WRITE);
>>> rdev_dec_pending(rdev, mddev);
>>> }
>>> }
>>> @@ -2461,7 +2462,8 @@ static void fix_read_error(struct r1conf *conf,
>>> struct r1bio *r1_bio)
>>> !test_bit(Faulty, &rdev->flags)) {
>>> atomic_inc(&rdev->nr_pending);
>>> if (r1_sync_page_io(rdev, sect, s,
>>> - conf->tmppage,
>>> REQ_OP_READ)) {
>>> +
>>> folio_page(conf->tmpfolio, 0),
>>> + REQ_OP_READ)) {
>>> atomic_add(s,
>>> &rdev->corrected_errors);
>>> pr_info("md/raid1:%s: read
>>> error corrected (%d sectors at %llu on %pg)\n",
>>> mdname(mddev), s,
>>> @@ -3120,8 +3122,8 @@ static struct r1conf *setup_conf(struct mddev *mddev)
>>> if (!conf->mirrors)
>>> goto abort;
>>>
>>> - conf->tmppage = alloc_page(GFP_KERNEL);
>>> - if (!conf->tmppage)
>>> + conf->tmpfolio = folio_alloc(GFP_KERNEL, 0);
>>> + if (!conf->tmpfolio)
>>> goto abort;
>>>
>>> r1bio_size = offsetof(struct r1bio, bios[mddev->raid_disks * 2]);
>>> @@ -3196,7 +3198,7 @@ static struct r1conf *setup_conf(struct mddev *mddev)
>>> if (conf) {
>>> mempool_destroy(conf->r1bio_pool);
>>> kfree(conf->mirrors);
>>> - safe_put_page(conf->tmppage);
>>> + folio_put(conf->tmpfolio);
>>> kfree(conf->nr_pending);
>>> kfree(conf->nr_waiting);
>>> kfree(conf->nr_queued);
>>> @@ -3310,7 +3312,7 @@ static void raid1_free(struct mddev *mddev, void
>>> *priv)
>>>
>>> mempool_destroy(conf->r1bio_pool);
>>> kfree(conf->mirrors);
>>> - safe_put_page(conf->tmppage);
>>> + folio_put(conf->tmpfolio);
>>> kfree(conf->nr_pending);
>>> kfree(conf->nr_waiting);
>>> kfree(conf->nr_queued);
>>> --
>>> 2.39.2
>>>
>> Hi Nan
>>
>> Same question for patch04 and patch05, tmpage is used in read io path.
>> From the cover letter, this patch set wants to resolve the multi pages
>> in sync io path. Is it better to keep them for your future patch set?
>>
>> Best Regards
>> Xiao
>>
>> Xiao
>
>
> After reading patch06, I understand here. r1_sync_page_io needs to change
> to r1_sync_folio_io to handle sync read error. Please ignore my above
> comments. patch04 and patch05 look good to me.
>
> Best Regards
>
> Xiao
>
Thanks for your patient review.
--
Thanks,
Nan
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH 05/15] md/raid10: use folio for tmppage
2025-12-17 11:59 [PATCH 00/15] folio support for sync I/O in RAID linan666
` (3 preceding siblings ...)
2025-12-17 12:00 ` [PATCH 04/15] md/raid1: use folio for tmppage linan666
@ 2025-12-17 12:00 ` linan666
2025-12-17 12:00 ` [PATCH 06/15] md/raid1,raid10: use folio for sync path IO linan666
` (9 subsequent siblings)
14 siblings, 0 replies; 26+ messages in thread
From: linan666 @ 2025-12-17 12:00 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, xni, linan666, yangerkun, yi.zhang
From: Li Nan <linan122@huawei.com>
Convert tmppage to tmpfolio and use it throughout in raid10.
Signed-off-by: Li Nan <linan122@huawei.com>
---
drivers/md/raid10.h | 2 +-
drivers/md/raid10.c | 37 +++++++++++++++++++------------------
2 files changed, 20 insertions(+), 19 deletions(-)
diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h
index ec79d87fb92f..19f37439a4e2 100644
--- a/drivers/md/raid10.h
+++ b/drivers/md/raid10.h
@@ -89,7 +89,7 @@ struct r10conf {
mempool_t r10bio_pool;
mempool_t r10buf_pool;
- struct page *tmppage;
+ struct folio *tmpfolio;
struct bio_set bio_split;
/* When taking over an array from a different personality, we store
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 1e57d9ce98e7..09238dc9cde6 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -2581,13 +2581,13 @@ static void recovery_request_write(struct mddev *mddev, struct r10bio *r10_bio)
}
}
-static int r10_sync_page_io(struct md_rdev *rdev, sector_t sector,
- int sectors, struct page *page, enum req_op op)
+static int r10_sync_folio_io(struct md_rdev *rdev, sector_t sector,
+ int sectors, struct folio *folio, enum req_op op)
{
if (rdev_has_badblock(rdev, sector, sectors) &&
(op == REQ_OP_READ || test_bit(WriteErrorSeen, &rdev->flags)))
return -1;
- if (sync_page_io(rdev, sector, sectors << 9, page, op, false))
+ if (sync_folio_io(rdev, sector, sectors << 9, 0, folio, op, false))
/* success */
return 1;
if (op == REQ_OP_WRITE) {
@@ -2650,12 +2650,13 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
r10_bio->devs[sl].addr + sect,
s) == 0) {
atomic_inc(&rdev->nr_pending);
- success = sync_page_io(rdev,
- r10_bio->devs[sl].addr +
- sect,
- s<<9,
- conf->tmppage,
- REQ_OP_READ, false);
+ success = sync_folio_io(rdev,
+ r10_bio->devs[sl].addr +
+ sect,
+ s<<9,
+ 0,
+ conf->tmpfolio,
+ REQ_OP_READ, false);
rdev_dec_pending(rdev, mddev);
if (success)
break;
@@ -2698,10 +2699,10 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
continue;
atomic_inc(&rdev->nr_pending);
- if (r10_sync_page_io(rdev,
- r10_bio->devs[sl].addr +
- sect,
- s, conf->tmppage, REQ_OP_WRITE)
+ if (r10_sync_folio_io(rdev,
+ r10_bio->devs[sl].addr +
+ sect,
+ s, conf->tmpfolio, REQ_OP_WRITE)
== 0) {
/* Well, this device is dead */
pr_notice("md/raid10:%s: read correction write failed (%d sectors at %llu on %pg)\n",
@@ -2730,10 +2731,10 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
continue;
atomic_inc(&rdev->nr_pending);
- switch (r10_sync_page_io(rdev,
+ switch (r10_sync_folio_io(rdev,
r10_bio->devs[sl].addr +
sect,
- s, conf->tmppage, REQ_OP_READ)) {
+ s, conf->tmpfolio, REQ_OP_READ)) {
case 0:
/* Well, this device is dead */
pr_notice("md/raid10:%s: unable to read back corrected sectors (%d sectors at %llu on %pg)\n",
@@ -3841,7 +3842,7 @@ static void raid10_free_conf(struct r10conf *conf)
kfree(conf->mirrors);
kfree(conf->mirrors_old);
kfree(conf->mirrors_new);
- safe_put_page(conf->tmppage);
+ folio_put(conf->tmpfolio);
bioset_exit(&conf->bio_split);
kfree(conf);
}
@@ -3879,8 +3880,8 @@ static struct r10conf *setup_conf(struct mddev *mddev)
if (!conf->mirrors)
goto out;
- conf->tmppage = alloc_page(GFP_KERNEL);
- if (!conf->tmppage)
+ conf->tmpfolio = folio_alloc(GFP_KERNEL, 0);
+ if (!conf->tmpfolio)
goto out;
conf->geo = geo;
--
2.39.2
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH 06/15] md/raid1,raid10: use folio for sync path IO
2025-12-17 11:59 [PATCH 00/15] folio support for sync I/O in RAID linan666
` (4 preceding siblings ...)
2025-12-17 12:00 ` [PATCH 05/15] md/raid10: " linan666
@ 2025-12-17 12:00 ` linan666
2025-12-27 1:34 ` Li Nan
2026-01-20 15:53 ` Xiao Ni
2025-12-17 12:00 ` [PATCH 07/15] md: Clean up folio sync support related code linan666
` (8 subsequent siblings)
14 siblings, 2 replies; 26+ messages in thread
From: linan666 @ 2025-12-17 12:00 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, xni, linan666, yangerkun, yi.zhang
From: Li Nan <linan122@huawei.com>
Convert all IO on the sync path to use folios. Rename page-related
identifiers to match folio.
Retain some now-unnecessary while and for loops to minimize code
changes, clean them up in a subsequent patch.
Signed-off-by: Li Nan <linan122@huawei.com>
---
drivers/md/md.c | 2 +-
drivers/md/raid1-10.c | 60 ++++--------
drivers/md/raid1.c | 155 ++++++++++++++-----------------
drivers/md/raid10.c | 207 +++++++++++++++++++-----------------------
4 files changed, 179 insertions(+), 245 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 0732bbcdb95d..dac03b831efa 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -9409,7 +9409,7 @@ static bool sync_io_within_limit(struct mddev *mddev)
{
/*
* For raid456, sync IO is stripe(4k) per IO, for other levels, it's
- * RESYNC_PAGES(64k) per IO.
+ * RESYNC_BLOCK_SIZE(64k) per IO.
*/
return atomic_read(&mddev->recovery_active) <
(raid_is_456(mddev) ? 8 : 128) * sync_io_depth(mddev);
diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
index 260d7fd7ccbe..b8f2cc32606f 100644
--- a/drivers/md/raid1-10.c
+++ b/drivers/md/raid1-10.c
@@ -25,9 +25,9 @@
#define MAX_PLUG_BIO 32
/* for managing resync I/O pages */
-struct resync_pages {
+struct resync_folio {
void *raid_bio;
- struct page *pages[RESYNC_PAGES];
+ struct folio *folio;
};
struct raid1_plug_cb {
@@ -41,77 +41,55 @@ static void rbio_pool_free(void *rbio, void *data)
kfree(rbio);
}
-static inline int resync_alloc_pages(struct resync_pages *rp,
+static inline int resync_alloc_folio(struct resync_folio *rf,
gfp_t gfp_flags)
{
- int i;
-
- for (i = 0; i < RESYNC_PAGES; i++) {
- rp->pages[i] = alloc_page(gfp_flags);
- if (!rp->pages[i])
- goto out_free;
- }
+ rf->folio = folio_alloc(gfp_flags, get_order(RESYNC_BLOCK_SIZE));
+ if (!rf->folio)
+ return -ENOMEM;
return 0;
-
-out_free:
- while (--i >= 0)
- put_page(rp->pages[i]);
- return -ENOMEM;
}
-static inline void resync_free_pages(struct resync_pages *rp)
+static inline void resync_free_folio(struct resync_folio *rf)
{
- int i;
-
- for (i = 0; i < RESYNC_PAGES; i++)
- put_page(rp->pages[i]);
+ folio_put(rf->folio);
}
-static inline void resync_get_all_pages(struct resync_pages *rp)
+static inline void resync_get_all_folio(struct resync_folio *rf)
{
- int i;
-
- for (i = 0; i < RESYNC_PAGES; i++)
- get_page(rp->pages[i]);
+ folio_get(rf->folio);
}
-static inline struct page *resync_fetch_page(struct resync_pages *rp,
- unsigned idx)
+static inline struct folio *resync_fetch_folio(struct resync_folio *rf)
{
- if (WARN_ON_ONCE(idx >= RESYNC_PAGES))
- return NULL;
- return rp->pages[idx];
+ return rf->folio;
}
/*
- * 'strct resync_pages' stores actual pages used for doing the resync
+ * 'strct resync_folio' stores actual pages used for doing the resync
* IO, and it is per-bio, so make .bi_private points to it.
*/
-static inline struct resync_pages *get_resync_pages(struct bio *bio)
+static inline struct resync_folio *get_resync_folio(struct bio *bio)
{
return bio->bi_private;
}
/* generally called after bio_reset() for reseting bvec */
-static void md_bio_reset_resync_pages(struct bio *bio, struct resync_pages *rp,
+static void md_bio_reset_resync_folio(struct bio *bio, struct resync_folio *rf,
int size)
{
- int idx = 0;
-
/* initialize bvec table again */
do {
- struct page *page = resync_fetch_page(rp, idx);
- int len = min_t(int, size, PAGE_SIZE);
+ struct folio *folio = resync_fetch_folio(rf);
+ int len = min_t(int, size, RESYNC_BLOCK_SIZE);
- if (WARN_ON(!bio_add_page(bio, page, len, 0))) {
+ if (WARN_ON(!bio_add_folio(bio, folio, len, 0))) {
bio->bi_status = BLK_STS_RESOURCE;
bio_endio(bio);
return;
}
-
- size -= len;
- } while (idx++ < RESYNC_PAGES && size > 0);
+ } while (0);
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 43453f1a04f4..370bdecf5487 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -120,11 +120,11 @@ static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi)
/*
* for resync bio, r1bio pointer can be retrieved from the per-bio
- * 'struct resync_pages'.
+ * 'struct resync_folio'.
*/
static inline struct r1bio *get_resync_r1bio(struct bio *bio)
{
- return get_resync_pages(bio)->raid_bio;
+ return get_resync_folio(bio)->raid_bio;
}
static void *r1bio_pool_alloc(gfp_t gfp_flags, struct r1conf *conf)
@@ -146,70 +146,69 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data)
struct r1conf *conf = data;
struct r1bio *r1_bio;
struct bio *bio;
- int need_pages;
+ int need_folio;
int j;
- struct resync_pages *rps;
+ struct resync_folio *rfs;
r1_bio = r1bio_pool_alloc(gfp_flags, conf);
if (!r1_bio)
return NULL;
- rps = kmalloc_array(conf->raid_disks * 2, sizeof(struct resync_pages),
+ rfs = kmalloc_array(conf->raid_disks * 2, sizeof(struct resync_folio),
gfp_flags);
- if (!rps)
+ if (!rfs)
goto out_free_r1bio;
/*
* Allocate bios : 1 for reading, n-1 for writing
*/
for (j = conf->raid_disks * 2; j-- ; ) {
- bio = bio_kmalloc(RESYNC_PAGES, gfp_flags);
+ bio = bio_kmalloc(1, gfp_flags);
if (!bio)
goto out_free_bio;
- bio_init_inline(bio, NULL, RESYNC_PAGES, 0);
+ bio_init_inline(bio, NULL, 1, 0);
r1_bio->bios[j] = bio;
}
/*
- * Allocate RESYNC_PAGES data pages and attach them to
- * the first bio.
+ * Allocate data folio and attach them to the first bio.
* If this is a user-requested check/repair, allocate
- * RESYNC_PAGES for each bio.
+ * folio for each bio.
*/
if (test_bit(MD_RECOVERY_REQUESTED, &conf->mddev->recovery))
- need_pages = conf->raid_disks * 2;
+ need_folio = conf->raid_disks * 2;
else
- need_pages = 1;
+ need_folio = 1;
for (j = 0; j < conf->raid_disks * 2; j++) {
- struct resync_pages *rp = &rps[j];
+ struct resync_folio *rf = &rfs[j];
bio = r1_bio->bios[j];
- if (j < need_pages) {
- if (resync_alloc_pages(rp, gfp_flags))
- goto out_free_pages;
+ if (j < need_folio) {
+ if (resync_alloc_folio(rf, gfp_flags))
+ goto out_free_folio;
} else {
- memcpy(rp, &rps[0], sizeof(*rp));
- resync_get_all_pages(rp);
+ memcpy(rf, &rfs[0], sizeof(*rf));
+ resync_get_all_folio(rf);
}
- rp->raid_bio = r1_bio;
- bio->bi_private = rp;
+ rf->raid_bio = r1_bio;
+ bio->bi_private = rf;
}
r1_bio->master_bio = NULL;
return r1_bio;
-out_free_pages:
+out_free_folio:
while (--j >= 0)
- resync_free_pages(&rps[j]);
+ resync_free_folio(&rfs[j]);
out_free_bio:
while (++j < conf->raid_disks * 2) {
bio_uninit(r1_bio->bios[j]);
kfree(r1_bio->bios[j]);
}
- kfree(rps);
+ kfree(rfs);
out_free_r1bio:
rbio_pool_free(r1_bio, data);
@@ -221,17 +220,17 @@ static void r1buf_pool_free(void *__r1_bio, void *data)
struct r1conf *conf = data;
int i;
struct r1bio *r1bio = __r1_bio;
- struct resync_pages *rp = NULL;
+ struct resync_folio *rf = NULL;
for (i = conf->raid_disks * 2; i--; ) {
- rp = get_resync_pages(r1bio->bios[i]);
- resync_free_pages(rp);
+ rf = get_resync_folio(r1bio->bios[i]);
+ resync_free_folio(rf);
bio_uninit(r1bio->bios[i]);
kfree(r1bio->bios[i]);
}
- /* resync pages array stored in the 1st bio's .bi_private */
- kfree(rp);
+ /* resync folio stored in the 1st bio's .bi_private */
+ kfree(rf);
rbio_pool_free(r1bio, data);
}
@@ -2095,10 +2094,10 @@ static void end_sync_write(struct bio *bio)
put_sync_write_buf(r1_bio);
}
-static int r1_sync_page_io(struct md_rdev *rdev, sector_t sector,
- int sectors, struct page *page, blk_opf_t rw)
+static int r1_sync_folio_io(struct md_rdev *rdev, sector_t sector, int sectors,
+ int off, struct folio *folio, blk_opf_t rw)
{
- if (sync_page_io(rdev, sector, sectors << 9, page, rw, false))
+ if (sync_folio_io(rdev, sector, sectors << 9, off, folio, rw, false))
/* success */
return 1;
if (rw == REQ_OP_WRITE) {
@@ -2129,10 +2128,10 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
struct mddev *mddev = r1_bio->mddev;
struct r1conf *conf = mddev->private;
struct bio *bio = r1_bio->bios[r1_bio->read_disk];
- struct page **pages = get_resync_pages(bio)->pages;
+ struct folio *folio = get_resync_folio(bio)->folio;
sector_t sect = r1_bio->sector;
int sectors = r1_bio->sectors;
- int idx = 0;
+ int off = 0;
struct md_rdev *rdev;
rdev = conf->mirrors[r1_bio->read_disk].rdev;
@@ -2162,9 +2161,8 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
* active, and resync is currently active
*/
rdev = conf->mirrors[d].rdev;
- if (sync_page_io(rdev, sect, s<<9,
- pages[idx],
- REQ_OP_READ, false)) {
+ if (sync_folio_io(rdev, sect, s<<9, off, folio,
+ REQ_OP_READ, false)) {
success = 1;
break;
}
@@ -2197,7 +2195,7 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
/* Try next page */
sectors -= s;
sect += s;
- idx++;
+ off += s << 9;
continue;
}
@@ -2210,8 +2208,7 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
if (r1_bio->bios[d]->bi_end_io != end_sync_read)
continue;
rdev = conf->mirrors[d].rdev;
- if (r1_sync_page_io(rdev, sect, s,
- pages[idx],
+ if (r1_sync_folio_io(rdev, sect, s, off, folio,
REQ_OP_WRITE) == 0) {
r1_bio->bios[d]->bi_end_io = NULL;
rdev_dec_pending(rdev, mddev);
@@ -2225,14 +2222,13 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
if (r1_bio->bios[d]->bi_end_io != end_sync_read)
continue;
rdev = conf->mirrors[d].rdev;
- if (r1_sync_page_io(rdev, sect, s,
- pages[idx],
+ if (r1_sync_folio_io(rdev, sect, s, off, folio,
REQ_OP_READ) != 0)
atomic_add(s, &rdev->corrected_errors);
}
sectors -= s;
sect += s;
- idx ++;
+ off += s << 9;
}
set_bit(R1BIO_Uptodate, &r1_bio->state);
bio->bi_status = 0;
@@ -2252,14 +2248,12 @@ static void process_checks(struct r1bio *r1_bio)
struct r1conf *conf = mddev->private;
int primary;
int i;
- int vcnt;
/* Fix variable parts of all bios */
- vcnt = (r1_bio->sectors + PAGE_SIZE / 512 - 1) >> (PAGE_SHIFT - 9);
for (i = 0; i < conf->raid_disks * 2; i++) {
blk_status_t status;
struct bio *b = r1_bio->bios[i];
- struct resync_pages *rp = get_resync_pages(b);
+ struct resync_folio *rf = get_resync_folio(b);
if (b->bi_end_io != end_sync_read)
continue;
/* fixup the bio for reuse, but preserve errno */
@@ -2269,11 +2263,11 @@ static void process_checks(struct r1bio *r1_bio)
b->bi_iter.bi_sector = r1_bio->sector +
conf->mirrors[i].rdev->data_offset;
b->bi_end_io = end_sync_read;
- rp->raid_bio = r1_bio;
- b->bi_private = rp;
+ rf->raid_bio = r1_bio;
+ b->bi_private = rf;
/* initialize bvec table again */
- md_bio_reset_resync_pages(b, rp, r1_bio->sectors << 9);
+ md_bio_reset_resync_folio(b, rf, r1_bio->sectors << 9);
}
for (primary = 0; primary < conf->raid_disks * 2; primary++)
if (r1_bio->bios[primary]->bi_end_io == end_sync_read &&
@@ -2284,44 +2278,30 @@ static void process_checks(struct r1bio *r1_bio)
}
r1_bio->read_disk = primary;
for (i = 0; i < conf->raid_disks * 2; i++) {
- int j = 0;
struct bio *pbio = r1_bio->bios[primary];
struct bio *sbio = r1_bio->bios[i];
blk_status_t status = sbio->bi_status;
- struct page **ppages = get_resync_pages(pbio)->pages;
- struct page **spages = get_resync_pages(sbio)->pages;
- struct bio_vec *bi;
- int page_len[RESYNC_PAGES] = { 0 };
- struct bvec_iter_all iter_all;
+ struct folio *pfolio = get_resync_folio(pbio)->folio;
+ struct folio *sfolio = get_resync_folio(sbio)->folio;
if (sbio->bi_end_io != end_sync_read)
continue;
/* Now we can 'fixup' the error value */
sbio->bi_status = 0;
- bio_for_each_segment_all(bi, sbio, iter_all)
- page_len[j++] = bi->bv_len;
-
- if (!status) {
- for (j = vcnt; j-- ; ) {
- if (memcmp(page_address(ppages[j]),
- page_address(spages[j]),
- page_len[j]))
- break;
- }
- } else
- j = 0;
- if (j >= 0)
+ if (status || memcmp(folio_address(pfolio),
+ folio_address(sfolio),
+ r1_bio->sectors << 9)) {
atomic64_add(r1_bio->sectors, &mddev->resync_mismatches);
- if (j < 0 || (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)
- && !status)) {
- /* No need to write to this device. */
- sbio->bi_end_io = NULL;
- rdev_dec_pending(conf->mirrors[i].rdev, mddev);
- continue;
+ if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery)) {
+ bio_copy_data(sbio, pbio);
+ continue;
+ }
}
- bio_copy_data(sbio, pbio);
+ /* No need to write to this device. */
+ sbio->bi_end_io = NULL;
+ rdev_dec_pending(conf->mirrors[i].rdev, mddev);
}
}
@@ -2446,9 +2426,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
if (rdev &&
!test_bit(Faulty, &rdev->flags)) {
atomic_inc(&rdev->nr_pending);
- r1_sync_page_io(rdev, sect, s,
- folio_page(conf->tmpfolio, 0),
- REQ_OP_WRITE);
+ r1_sync_folio_io(rdev, sect, s, 0,
+ conf->tmpfolio, REQ_OP_WRITE);
rdev_dec_pending(rdev, mddev);
}
}
@@ -2461,9 +2440,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
if (rdev &&
!test_bit(Faulty, &rdev->flags)) {
atomic_inc(&rdev->nr_pending);
- if (r1_sync_page_io(rdev, sect, s,
- folio_page(conf->tmpfolio, 0),
- REQ_OP_READ)) {
+ if (r1_sync_folio_io(rdev, sect, s, 0,
+ conf->tmpfolio, REQ_OP_READ)) {
atomic_add(s, &rdev->corrected_errors);
pr_info("md/raid1:%s: read error corrected (%d sectors at %llu on %pg)\n",
mdname(mddev), s,
@@ -2799,7 +2777,6 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
int good_sectors = RESYNC_SECTORS;
int min_bad = 0; /* number of sectors that are bad in all devices */
int idx = sector_to_idx(sector_nr);
- int page_idx = 0;
if (!mempool_initialized(&conf->r1buf_pool))
if (init_resync(conf))
@@ -3003,8 +2980,8 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
nr_sectors = 0;
sync_blocks = 0;
do {
- struct page *page;
- int len = PAGE_SIZE;
+ struct folio *folio;
+ int len = RESYNC_BLOCK_SIZE;
if (sector_nr + (len>>9) > max_sector)
len = (max_sector - sector_nr) << 9;
if (len == 0)
@@ -3020,24 +2997,24 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
}
for (i = 0 ; i < conf->raid_disks * 2; i++) {
- struct resync_pages *rp;
+ struct resync_folio *rf;
bio = r1_bio->bios[i];
- rp = get_resync_pages(bio);
+ rf = get_resync_folio(bio);
if (bio->bi_end_io) {
- page = resync_fetch_page(rp, page_idx);
+ folio = resync_fetch_folio(rf);
/*
* won't fail because the vec table is big
* enough to hold all these pages
*/
- __bio_add_page(bio, page, len, 0);
+ bio_add_folio_nofail(bio, folio, len, 0);
}
}
nr_sectors += len>>9;
sector_nr += len>>9;
sync_blocks -= (len>>9);
- } while (++page_idx < RESYNC_PAGES);
+ } while (0);
r1_bio->sectors = nr_sectors;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 09238dc9cde6..c93706806358 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -96,11 +96,11 @@ static void end_reshape(struct r10conf *conf);
/*
* for resync bio, r10bio pointer can be retrieved from the per-bio
- * 'struct resync_pages'.
+ * 'struct resync_folio'.
*/
static inline struct r10bio *get_resync_r10bio(struct bio *bio)
{
- return get_resync_pages(bio)->raid_bio;
+ return get_resync_folio(bio)->raid_bio;
}
static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
@@ -133,8 +133,8 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
struct r10bio *r10_bio;
struct bio *bio;
int j;
- int nalloc, nalloc_rp;
- struct resync_pages *rps;
+ int nalloc, nalloc_rf;
+ struct resync_folio *rfs;
r10_bio = r10bio_pool_alloc(gfp_flags, conf);
if (!r10_bio)
@@ -148,58 +148,57 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
/* allocate once for all bios */
if (!conf->have_replacement)
- nalloc_rp = nalloc;
+ nalloc_rf = nalloc;
else
- nalloc_rp = nalloc * 2;
- rps = kmalloc_array(nalloc_rp, sizeof(struct resync_pages), gfp_flags);
- if (!rps)
+ nalloc_rf = nalloc * 2;
+ rfs = kmalloc_array(nalloc_rf, sizeof(struct resync_folio), gfp_flags);
+ if (!rfs)
goto out_free_r10bio;
/*
* Allocate bios.
*/
for (j = nalloc ; j-- ; ) {
- bio = bio_kmalloc(RESYNC_PAGES, gfp_flags);
+ bio = bio_kmalloc(1, gfp_flags);
if (!bio)
goto out_free_bio;
- bio_init_inline(bio, NULL, RESYNC_PAGES, 0);
+ bio_init_inline(bio, NULL, 1, 0);
r10_bio->devs[j].bio = bio;
if (!conf->have_replacement)
continue;
- bio = bio_kmalloc(RESYNC_PAGES, gfp_flags);
+ bio = bio_kmalloc(1, gfp_flags);
if (!bio)
goto out_free_bio;
- bio_init_inline(bio, NULL, RESYNC_PAGES, 0);
+ bio_init_inline(bio, NULL, 1, 0);
r10_bio->devs[j].repl_bio = bio;
}
/*
- * Allocate RESYNC_PAGES data pages and attach them
- * where needed.
+ * Allocate data folio and attach them where needed.
*/
for (j = 0; j < nalloc; j++) {
struct bio *rbio = r10_bio->devs[j].repl_bio;
- struct resync_pages *rp, *rp_repl;
+ struct resync_folio *rf, *rf_repl;
- rp = &rps[j];
+ rf = &rfs[j];
if (rbio)
- rp_repl = &rps[nalloc + j];
+ rf_repl = &rfs[nalloc + j];
bio = r10_bio->devs[j].bio;
if (!j || test_bit(MD_RECOVERY_SYNC,
&conf->mddev->recovery)) {
- if (resync_alloc_pages(rp, gfp_flags))
+ if (resync_alloc_folio(rf, gfp_flags))
goto out_free_pages;
} else {
- memcpy(rp, &rps[0], sizeof(*rp));
- resync_get_all_pages(rp);
+ memcpy(rf, &rfs[0], sizeof(*rf));
+ resync_get_all_folio(rf);
}
- rp->raid_bio = r10_bio;
- bio->bi_private = rp;
+ rf->raid_bio = r10_bio;
+ bio->bi_private = rf;
if (rbio) {
- memcpy(rp_repl, rp, sizeof(*rp));
- rbio->bi_private = rp_repl;
+ memcpy(rf_repl, rf, sizeof(*rf));
+ rbio->bi_private = rf_repl;
}
}
@@ -207,7 +206,7 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
out_free_pages:
while (--j >= 0)
- resync_free_pages(&rps[j]);
+ resync_free_folio(&rfs[j]);
j = 0;
out_free_bio:
@@ -219,7 +218,7 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
bio_uninit(r10_bio->devs[j].repl_bio);
kfree(r10_bio->devs[j].repl_bio);
}
- kfree(rps);
+ kfree(rfs);
out_free_r10bio:
rbio_pool_free(r10_bio, conf);
return NULL;
@@ -230,14 +229,14 @@ static void r10buf_pool_free(void *__r10_bio, void *data)
struct r10conf *conf = data;
struct r10bio *r10bio = __r10_bio;
int j;
- struct resync_pages *rp = NULL;
+ struct resync_folio *rf = NULL;
for (j = conf->copies; j--; ) {
struct bio *bio = r10bio->devs[j].bio;
if (bio) {
- rp = get_resync_pages(bio);
- resync_free_pages(rp);
+ rf = get_resync_folio(bio);
+ resync_free_folio(rf);
bio_uninit(bio);
kfree(bio);
}
@@ -250,7 +249,7 @@ static void r10buf_pool_free(void *__r10_bio, void *data)
}
/* resync pages array stored in the 1st bio's .bi_private */
- kfree(rp);
+ kfree(rf);
rbio_pool_free(r10bio, conf);
}
@@ -2342,8 +2341,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
struct r10conf *conf = mddev->private;
int i, first;
struct bio *tbio, *fbio;
- int vcnt;
- struct page **tpages, **fpages;
+ struct folio *tfolio, *ffolio;
atomic_set(&r10_bio->remaining, 1);
@@ -2359,14 +2357,13 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
fbio = r10_bio->devs[i].bio;
fbio->bi_iter.bi_size = r10_bio->sectors << 9;
fbio->bi_iter.bi_idx = 0;
- fpages = get_resync_pages(fbio)->pages;
+ ffolio = get_resync_folio(fbio)->folio;
- vcnt = (r10_bio->sectors + (PAGE_SIZE >> 9) - 1) >> (PAGE_SHIFT - 9);
/* now find blocks with errors */
for (i=0 ; i < conf->copies ; i++) {
- int j, d;
+ int d;
struct md_rdev *rdev;
- struct resync_pages *rp;
+ struct resync_folio *rf;
tbio = r10_bio->devs[i].bio;
@@ -2375,31 +2372,23 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
if (i == first)
continue;
- tpages = get_resync_pages(tbio)->pages;
+ tfolio = get_resync_folio(tbio)->folio;
d = r10_bio->devs[i].devnum;
rdev = conf->mirrors[d].rdev;
if (!r10_bio->devs[i].bio->bi_status) {
/* We know that the bi_io_vec layout is the same for
* both 'first' and 'i', so we just compare them.
- * All vec entries are PAGE_SIZE;
*/
- int sectors = r10_bio->sectors;
- for (j = 0; j < vcnt; j++) {
- int len = PAGE_SIZE;
- if (sectors < (len / 512))
- len = sectors * 512;
- if (memcmp(page_address(fpages[j]),
- page_address(tpages[j]),
- len))
- break;
- sectors -= len/512;
+ if (memcmp(folio_address(ffolio),
+ folio_address(tfolio),
+ r10_bio->sectors << 9)) {
+ atomic64_add(r10_bio->sectors,
+ &mddev->resync_mismatches);
+ if (test_bit(MD_RECOVERY_CHECK,
+ &mddev->recovery))
+ /* Don't fix anything. */
+ continue;
}
- if (j == vcnt)
- continue;
- atomic64_add(r10_bio->sectors, &mddev->resync_mismatches);
- if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
- /* Don't fix anything. */
- continue;
} else if (test_bit(FailFast, &rdev->flags)) {
/* Just give up on this device */
md_error(rdev->mddev, rdev);
@@ -2410,13 +2399,13 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
* First we need to fixup bv_offset, bv_len and
* bi_vecs, as the read request might have corrupted these
*/
- rp = get_resync_pages(tbio);
+ rf = get_resync_folio(tbio);
bio_reset(tbio, conf->mirrors[d].rdev->bdev, REQ_OP_WRITE);
- md_bio_reset_resync_pages(tbio, rp, fbio->bi_iter.bi_size);
+ md_bio_reset_resync_folio(tbio, rf, fbio->bi_iter.bi_size);
- rp->raid_bio = r10_bio;
- tbio->bi_private = rp;
+ rf->raid_bio = r10_bio;
+ tbio->bi_private = rf;
tbio->bi_iter.bi_sector = r10_bio->devs[i].addr;
tbio->bi_end_io = end_sync_write;
@@ -2476,10 +2465,9 @@ static void fix_recovery_read_error(struct r10bio *r10_bio)
struct bio *bio = r10_bio->devs[0].bio;
sector_t sect = 0;
int sectors = r10_bio->sectors;
- int idx = 0;
int dr = r10_bio->devs[0].devnum;
int dw = r10_bio->devs[1].devnum;
- struct page **pages = get_resync_pages(bio)->pages;
+ struct folio *folio = get_resync_folio(bio)->folio;
while (sectors) {
int s = sectors;
@@ -2492,19 +2480,21 @@ static void fix_recovery_read_error(struct r10bio *r10_bio)
rdev = conf->mirrors[dr].rdev;
addr = r10_bio->devs[0].addr + sect;
- ok = sync_page_io(rdev,
- addr,
- s << 9,
- pages[idx],
- REQ_OP_READ, false);
+ ok = sync_folio_io(rdev,
+ addr,
+ s << 9,
+ sect << 9,
+ folio,
+ REQ_OP_READ, false);
if (ok) {
rdev = conf->mirrors[dw].rdev;
addr = r10_bio->devs[1].addr + sect;
- ok = sync_page_io(rdev,
- addr,
- s << 9,
- pages[idx],
- REQ_OP_WRITE, false);
+ ok = sync_folio_io(rdev,
+ addr,
+ s << 9,
+ sect << 9,
+ folio,
+ REQ_OP_WRITE, false);
if (!ok) {
set_bit(WriteErrorSeen, &rdev->flags);
if (!test_and_set_bit(WantReplacement,
@@ -2539,7 +2529,6 @@ static void fix_recovery_read_error(struct r10bio *r10_bio)
sectors -= s;
sect += s;
- idx++;
}
}
@@ -3174,7 +3163,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
int max_sync = RESYNC_SECTORS;
sector_t sync_blocks;
sector_t chunk_mask = conf->geo.chunk_mask;
- int page_idx = 0;
/*
* Allow skipping a full rebuild for incremental assembly
@@ -3277,7 +3265,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
* with 2 bios in each, that correspond to the bios in the main one.
* In this case, the subordinate r10bios link back through a
* borrowed master_bio pointer, and the counter in the master
- * includes a ref from each subordinate.
+ * bio_add_folio includes a ref from each subordinate.
*/
/* First, we decide what to do and set ->bi_end_io
* To end_sync_read if we want to read, and
@@ -3642,25 +3630,26 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
if (sector_nr + max_sync < max_sector)
max_sector = sector_nr + max_sync;
do {
- struct page *page;
- int len = PAGE_SIZE;
+ int len = RESYNC_BLOCK_SIZE;
+
if (sector_nr + (len>>9) > max_sector)
len = (max_sector - sector_nr) << 9;
if (len == 0)
break;
for (bio= biolist ; bio ; bio=bio->bi_next) {
- struct resync_pages *rp = get_resync_pages(bio);
- page = resync_fetch_page(rp, page_idx);
- if (WARN_ON(!bio_add_page(bio, page, len, 0))) {
+ 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))) {
bio->bi_status = BLK_STS_RESOURCE;
bio_endio(bio);
*skipped = 1;
- return max_sync;
+ return len;
}
}
nr_sectors += len>>9;
sector_nr += len>>9;
- } while (++page_idx < RESYNC_PAGES);
+ } while (0);
r10_bio->sectors = nr_sectors;
if (mddev_is_clustered(mddev) &&
@@ -4578,7 +4567,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
int *skipped)
{
/* We simply copy at most one chunk (smallest of old and new)
- * at a time, possibly less if that exceeds RESYNC_PAGES,
+ * at a time, possibly less if that exceeds RESYNC_BLOCK_SIZE,
* or we hit a bad block or something.
* This might mean we pause for normal IO in the middle of
* a chunk, but that is not a problem as mddev->reshape_position
@@ -4618,14 +4607,13 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
struct r10bio *r10_bio;
sector_t next, safe, last;
int max_sectors;
- int nr_sectors;
int s;
struct md_rdev *rdev;
int need_flush = 0;
struct bio *blist;
struct bio *bio, *read_bio;
int sectors_done = 0;
- struct page **pages;
+ struct folio *folio;
if (sector_nr == 0) {
/* If restarting in the middle, skip the initial sectors */
@@ -4741,7 +4729,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
return sectors_done;
}
- read_bio = bio_alloc_bioset(rdev->bdev, RESYNC_PAGES, REQ_OP_READ,
+ read_bio = bio_alloc_bioset(rdev->bdev, 1, REQ_OP_READ,
GFP_KERNEL, &mddev->bio_set);
read_bio->bi_iter.bi_sector = (r10_bio->devs[r10_bio->read_slot].addr
+ rdev->data_offset);
@@ -4805,32 +4793,23 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
blist = b;
}
- /* Now add as many pages as possible to all of these bios. */
+ /* Now add folio to all of these bios. */
- nr_sectors = 0;
- pages = get_resync_pages(r10_bio->devs[0].bio)->pages;
- for (s = 0 ; s < max_sectors; s += PAGE_SIZE >> 9) {
- struct page *page = pages[s / (PAGE_SIZE >> 9)];
- int len = (max_sectors - s) << 9;
- if (len > PAGE_SIZE)
- len = PAGE_SIZE;
- for (bio = blist; bio ; bio = bio->bi_next) {
- if (WARN_ON(!bio_add_page(bio, page, len, 0))) {
- bio->bi_status = BLK_STS_RESOURCE;
- bio_endio(bio);
- return sectors_done;
- }
+ folio = get_resync_folio(r10_bio->devs[0].bio)->folio;
+ for (bio = blist; bio ; bio = bio->bi_next) {
+ if (WARN_ON(!bio_add_folio(bio, folio, max_sectors, 0))) {
+ bio->bi_status = BLK_STS_RESOURCE;
+ bio_endio(bio);
+ return sectors_done;
}
- sector_nr += len >> 9;
- nr_sectors += len >> 9;
}
- r10_bio->sectors = nr_sectors;
+ r10_bio->sectors = max_sectors >> 9;
/* Now submit the read */
atomic_inc(&r10_bio->remaining);
read_bio->bi_next = NULL;
submit_bio_noacct(read_bio);
- sectors_done += nr_sectors;
+ sectors_done += max_sectors;
if (sector_nr <= last)
goto read_more;
@@ -4932,8 +4911,8 @@ static int handle_reshape_read_error(struct mddev *mddev,
struct r10conf *conf = mddev->private;
struct r10bio *r10b;
int slot = 0;
- int idx = 0;
- struct page **pages;
+ int sect = 0;
+ struct folio *folio;
r10b = kmalloc(struct_size(r10b, devs, conf->copies), GFP_NOIO);
if (!r10b) {
@@ -4941,8 +4920,8 @@ static int handle_reshape_read_error(struct mddev *mddev,
return -ENOMEM;
}
- /* reshape IOs share pages from .devs[0].bio */
- pages = get_resync_pages(r10_bio->devs[0].bio)->pages;
+ /* reshape IOs share folio from .devs[0].bio */
+ folio = get_resync_folio(r10_bio->devs[0].bio)->folio;
r10b->sector = r10_bio->sector;
__raid10_find_phys(&conf->prev, r10b);
@@ -4958,19 +4937,19 @@ static int handle_reshape_read_error(struct mddev *mddev,
while (!success) {
int d = r10b->devs[slot].devnum;
struct md_rdev *rdev = conf->mirrors[d].rdev;
- sector_t addr;
if (rdev == NULL ||
test_bit(Faulty, &rdev->flags) ||
!test_bit(In_sync, &rdev->flags))
goto failed;
- addr = r10b->devs[slot].addr + idx * PAGE_SIZE;
atomic_inc(&rdev->nr_pending);
- success = sync_page_io(rdev,
- addr,
- s << 9,
- pages[idx],
- REQ_OP_READ, false);
+ success = sync_folio_io(rdev,
+ r10b->devs[slot].addr +
+ sect,
+ s << 9,
+ sect << 9,
+ folio,
+ REQ_OP_READ, false);
rdev_dec_pending(rdev, mddev);
if (success)
break;
@@ -4989,7 +4968,7 @@ static int handle_reshape_read_error(struct mddev *mddev,
return -EIO;
}
sectors -= s;
- idx++;
+ sect += s;
}
kfree(r10b);
return 0;
--
2.39.2
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH 06/15] md/raid1,raid10: use folio for sync path IO
2025-12-17 12:00 ` [PATCH 06/15] md/raid1,raid10: use folio for sync path IO linan666
@ 2025-12-27 1:34 ` Li Nan
2026-01-20 15:53 ` Xiao Ni
1 sibling, 0 replies; 26+ messages in thread
From: Li Nan @ 2025-12-27 1:34 UTC (permalink / raw)
To: linan666, song, yukuai; +Cc: linux-raid, linux-kernel, xni, yangerkun, yi.zhang
在 2025/12/17 20:00, linan666@huaweicloud.com 写道:
> From: Li Nan <linan122@huawei.com>
>
> Convert all IO on the sync path to use folios. Rename page-related
> identifiers to match folio.
>
> Retain some now-unnecessary while and for loops to minimize code
> changes, clean them up in a subsequent patch.
>
> Signed-off-by: Li Nan <linan122@huawei.com>
> ---
> drivers/md/md.c | 2 +-
> drivers/md/raid1-10.c | 60 ++++--------
> drivers/md/raid1.c | 155 ++++++++++++++-----------------
> drivers/md/raid10.c | 207 +++++++++++++++++++-----------------------
> 4 files changed, 179 insertions(+), 245 deletions(-)
>
This patch misses modifications to functions raid1_alloc_init_r1buf() and
raid10_alloc_init_r10buf(). They will be included with other suggestions in v2.
static struct r1bio *raid1_alloc_init_r1buf(struct r1conf *conf)
{
struct r1bio *r1bio = mempool_alloc(&conf->r1buf_pool, GFP_NOIO);
- struct resync_pages *rps;
+ struct resync_folio *rfs;
struct bio *bio;
int i;
static struct r10bio *raid10_alloc_init_r10buf(struct r10conf *conf)
{
struct r10bio *r10bio = mempool_alloc(&conf->r10buf_pool, GFP_NOIO);
- struct rsync_pages *rp;
+ struct resync_folio *rf;
struct bio *bio;
int nalloc;
int i;
--
Thanks,
Nan
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH 06/15] md/raid1,raid10: use folio for sync path IO
2025-12-17 12:00 ` [PATCH 06/15] md/raid1,raid10: use folio for sync path IO linan666
2025-12-27 1:34 ` Li Nan
@ 2026-01-20 15:53 ` Xiao Ni
2026-01-22 2:12 ` Li Nan
1 sibling, 1 reply; 26+ messages in thread
From: Xiao Ni @ 2026-01-20 15:53 UTC (permalink / raw)
To: linan666; +Cc: song, yukuai, linux-raid, linux-kernel, yangerkun, yi.zhang
On Wed, Dec 17, 2025 at 8:11 PM <linan666@huaweicloud.com> wrote:
>
> From: Li Nan <linan122@huawei.com>
>
> Convert all IO on the sync path to use folios. Rename page-related
> identifiers to match folio.
>
> Retain some now-unnecessary while and for loops to minimize code
> changes, clean them up in a subsequent patch.
>
> Signed-off-by: Li Nan <linan122@huawei.com>
> ---
> drivers/md/md.c | 2 +-
> drivers/md/raid1-10.c | 60 ++++--------
> drivers/md/raid1.c | 155 ++++++++++++++-----------------
> drivers/md/raid10.c | 207 +++++++++++++++++++-----------------------
> 4 files changed, 179 insertions(+), 245 deletions(-)
>
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index 0732bbcdb95d..dac03b831efa 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -9409,7 +9409,7 @@ static bool sync_io_within_limit(struct mddev *mddev)
> {
> /*
> * For raid456, sync IO is stripe(4k) per IO, for other levels, it's
> - * RESYNC_PAGES(64k) per IO.
> + * RESYNC_BLOCK_SIZE(64k) per IO.
> */
> return atomic_read(&mddev->recovery_active) <
> (raid_is_456(mddev) ? 8 : 128) * sync_io_depth(mddev);
> diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
> index 260d7fd7ccbe..b8f2cc32606f 100644
> --- a/drivers/md/raid1-10.c
> +++ b/drivers/md/raid1-10.c
> @@ -25,9 +25,9 @@
> #define MAX_PLUG_BIO 32
>
> /* for managing resync I/O pages */
> -struct resync_pages {
> +struct resync_folio {
> void *raid_bio;
> - struct page *pages[RESYNC_PAGES];
> + struct folio *folio;
> };
>
> struct raid1_plug_cb {
> @@ -41,77 +41,55 @@ static void rbio_pool_free(void *rbio, void *data)
> kfree(rbio);
> }
>
> -static inline int resync_alloc_pages(struct resync_pages *rp,
> +static inline int resync_alloc_folio(struct resync_folio *rf,
> gfp_t gfp_flags)
> {
> - int i;
> -
> - for (i = 0; i < RESYNC_PAGES; i++) {
> - rp->pages[i] = alloc_page(gfp_flags);
> - if (!rp->pages[i])
> - goto out_free;
> - }
> + rf->folio = folio_alloc(gfp_flags, get_order(RESYNC_BLOCK_SIZE));
> + if (!rf->folio)
> + return -ENOMEM;
Is it ok to add an error log here? Compare with the multipage
situation, the possibility of failure will be somewhat higher because
it needs to alloc a contiguous block of physical memory.
>
> return 0;
> -
> -out_free:
> - while (--i >= 0)
> - put_page(rp->pages[i]);
> - return -ENOMEM;
> }
>
> -static inline void resync_free_pages(struct resync_pages *rp)
> +static inline void resync_free_folio(struct resync_folio *rf)
> {
> - int i;
> -
> - for (i = 0; i < RESYNC_PAGES; i++)
> - put_page(rp->pages[i]);
> + folio_put(rf->folio);
> }
>
> -static inline void resync_get_all_pages(struct resync_pages *rp)
> +static inline void resync_get_all_folio(struct resync_folio *rf)
> {
> - int i;
> -
> - for (i = 0; i < RESYNC_PAGES; i++)
> - get_page(rp->pages[i]);
> + folio_get(rf->folio);
> }
>
> -static inline struct page *resync_fetch_page(struct resync_pages *rp,
> - unsigned idx)
> +static inline struct folio *resync_fetch_folio(struct resync_folio *rf)
> {
> - if (WARN_ON_ONCE(idx >= RESYNC_PAGES))
> - return NULL;
> - return rp->pages[idx];
> + return rf->folio;
> }
>
> /*
> - * 'strct resync_pages' stores actual pages used for doing the resync
> + * 'strct resync_folio' stores actual pages used for doing the resync
> * IO, and it is per-bio, so make .bi_private points to it.
> */
> -static inline struct resync_pages *get_resync_pages(struct bio *bio)
> +static inline struct resync_folio *get_resync_folio(struct bio *bio)
> {
> return bio->bi_private;
> }
>
> /* generally called after bio_reset() for reseting bvec */
> -static void md_bio_reset_resync_pages(struct bio *bio, struct resync_pages *rp,
> +static void md_bio_reset_resync_folio(struct bio *bio, struct resync_folio *rf,
> int size)
> {
> - int idx = 0;
> -
> /* initialize bvec table again */
> do {
> - struct page *page = resync_fetch_page(rp, idx);
> - int len = min_t(int, size, PAGE_SIZE);
> + struct folio *folio = resync_fetch_folio(rf);
> + int len = min_t(int, size, RESYNC_BLOCK_SIZE);
>
> - if (WARN_ON(!bio_add_page(bio, page, len, 0))) {
> + if (WARN_ON(!bio_add_folio(bio, folio, len, 0))) {
Is it ok to use bio_add_folio(bio, folio, RESYNC_BLOCK_SIZE, 0)
directly here? It removes `size -= len` below, so it's not useless to
compare size and RESYNC_BLOCK_SIZE above?
> bio->bi_status = BLK_STS_RESOURCE;
> bio_endio(bio);
> return;
> }
> -
> - size -= len;
> - } while (idx++ < RESYNC_PAGES && size > 0);
> + } while (0);
> }
>
>
> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> index 43453f1a04f4..370bdecf5487 100644
> --- a/drivers/md/raid1.c
> +++ b/drivers/md/raid1.c
> @@ -120,11 +120,11 @@ static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi)
>
> /*
> * for resync bio, r1bio pointer can be retrieved from the per-bio
> - * 'struct resync_pages'.
> + * 'struct resync_folio'.
> */
> static inline struct r1bio *get_resync_r1bio(struct bio *bio)
> {
> - return get_resync_pages(bio)->raid_bio;
> + return get_resync_folio(bio)->raid_bio;
> }
>
> static void *r1bio_pool_alloc(gfp_t gfp_flags, struct r1conf *conf)
> @@ -146,70 +146,69 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data)
> struct r1conf *conf = data;
> struct r1bio *r1_bio;
> struct bio *bio;
> - int need_pages;
> + int need_folio;
> int j;
> - struct resync_pages *rps;
> + struct resync_folio *rfs;
>
> r1_bio = r1bio_pool_alloc(gfp_flags, conf);
> if (!r1_bio)
> return NULL;
>
> - rps = kmalloc_array(conf->raid_disks * 2, sizeof(struct resync_pages),
> + rfs = kmalloc_array(conf->raid_disks * 2, sizeof(struct resync_folio),
> gfp_flags);
> - if (!rps)
> + if (!rfs)
> goto out_free_r1bio;
>
> /*
> * Allocate bios : 1 for reading, n-1 for writing
> */
> for (j = conf->raid_disks * 2; j-- ; ) {
> - bio = bio_kmalloc(RESYNC_PAGES, gfp_flags);
> + bio = bio_kmalloc(1, gfp_flags);
> if (!bio)
> goto out_free_bio;
> - bio_init_inline(bio, NULL, RESYNC_PAGES, 0);
> + bio_init_inline(bio, NULL, 1, 0);
> r1_bio->bios[j] = bio;
> }
> /*
> - * Allocate RESYNC_PAGES data pages and attach them to
> - * the first bio.
> + * Allocate data folio and attach them to the first bio.
typo error
s/attach them/attach it/g
> * If this is a user-requested check/repair, allocate
> - * RESYNC_PAGES for each bio.
> + * folio for each bio.
> */
> if (test_bit(MD_RECOVERY_REQUESTED, &conf->mddev->recovery))
> - need_pages = conf->raid_disks * 2;
> + need_folio = conf->raid_disks * 2;
> else
> - need_pages = 1;
> + need_folio = 1;
> for (j = 0; j < conf->raid_disks * 2; j++) {
> - struct resync_pages *rp = &rps[j];
> + struct resync_folio *rf = &rfs[j];
>
> bio = r1_bio->bios[j];
>
> - if (j < need_pages) {
> - if (resync_alloc_pages(rp, gfp_flags))
> - goto out_free_pages;
> + if (j < need_folio) {
> + if (resync_alloc_folio(rf, gfp_flags))
> + goto out_free_folio;
> } else {
> - memcpy(rp, &rps[0], sizeof(*rp));
> - resync_get_all_pages(rp);
> + memcpy(rf, &rfs[0], sizeof(*rf));
> + resync_get_all_folio(rf);
> }
>
> - rp->raid_bio = r1_bio;
> - bio->bi_private = rp;
> + rf->raid_bio = r1_bio;
> + bio->bi_private = rf;
> }
>
> r1_bio->master_bio = NULL;
>
> return r1_bio;
>
> -out_free_pages:
> +out_free_folio:
> while (--j >= 0)
> - resync_free_pages(&rps[j]);
> + resync_free_folio(&rfs[j]);
>
> out_free_bio:
> while (++j < conf->raid_disks * 2) {
> bio_uninit(r1_bio->bios[j]);
> kfree(r1_bio->bios[j]);
> }
> - kfree(rps);
> + kfree(rfs);
>
> out_free_r1bio:
> rbio_pool_free(r1_bio, data);
> @@ -221,17 +220,17 @@ static void r1buf_pool_free(void *__r1_bio, void *data)
> struct r1conf *conf = data;
> int i;
> struct r1bio *r1bio = __r1_bio;
> - struct resync_pages *rp = NULL;
> + struct resync_folio *rf = NULL;
>
> for (i = conf->raid_disks * 2; i--; ) {
> - rp = get_resync_pages(r1bio->bios[i]);
> - resync_free_pages(rp);
> + rf = get_resync_folio(r1bio->bios[i]);
> + resync_free_folio(rf);
> bio_uninit(r1bio->bios[i]);
> kfree(r1bio->bios[i]);
> }
>
> - /* resync pages array stored in the 1st bio's .bi_private */
> - kfree(rp);
> + /* resync folio stored in the 1st bio's .bi_private */
> + kfree(rf);
>
> rbio_pool_free(r1bio, data);
> }
> @@ -2095,10 +2094,10 @@ static void end_sync_write(struct bio *bio)
> put_sync_write_buf(r1_bio);
> }
>
> -static int r1_sync_page_io(struct md_rdev *rdev, sector_t sector,
> - int sectors, struct page *page, blk_opf_t rw)
> +static int r1_sync_folio_io(struct md_rdev *rdev, sector_t sector, int sectors,
> + int off, struct folio *folio, blk_opf_t rw)
> {
> - if (sync_page_io(rdev, sector, sectors << 9, page, rw, false))
> + if (sync_folio_io(rdev, sector, sectors << 9, off, folio, rw, false))
> /* success */
> return 1;
> if (rw == REQ_OP_WRITE) {
> @@ -2129,10 +2128,10 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
> struct mddev *mddev = r1_bio->mddev;
> struct r1conf *conf = mddev->private;
> struct bio *bio = r1_bio->bios[r1_bio->read_disk];
> - struct page **pages = get_resync_pages(bio)->pages;
> + struct folio *folio = get_resync_folio(bio)->folio;
> sector_t sect = r1_bio->sector;
> int sectors = r1_bio->sectors;
> - int idx = 0;
> + int off = 0;
> struct md_rdev *rdev;
>
> rdev = conf->mirrors[r1_bio->read_disk].rdev;
> @@ -2162,9 +2161,8 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
> * active, and resync is currently active
> */
> rdev = conf->mirrors[d].rdev;
> - if (sync_page_io(rdev, sect, s<<9,
> - pages[idx],
> - REQ_OP_READ, false)) {
> + if (sync_folio_io(rdev, sect, s<<9, off, folio,
> + REQ_OP_READ, false)) {
> success = 1;
> break;
> }
> @@ -2197,7 +2195,7 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
> /* Try next page */
> sectors -= s;
> sect += s;
> - idx++;
> + off += s << 9;
> continue;
> }
>
> @@ -2210,8 +2208,7 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
> if (r1_bio->bios[d]->bi_end_io != end_sync_read)
> continue;
> rdev = conf->mirrors[d].rdev;
> - if (r1_sync_page_io(rdev, sect, s,
> - pages[idx],
> + if (r1_sync_folio_io(rdev, sect, s, off, folio,
> REQ_OP_WRITE) == 0) {
> r1_bio->bios[d]->bi_end_io = NULL;
> rdev_dec_pending(rdev, mddev);
> @@ -2225,14 +2222,13 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
> if (r1_bio->bios[d]->bi_end_io != end_sync_read)
> continue;
> rdev = conf->mirrors[d].rdev;
> - if (r1_sync_page_io(rdev, sect, s,
> - pages[idx],
> + if (r1_sync_folio_io(rdev, sect, s, off, folio,
> REQ_OP_READ) != 0)
> atomic_add(s, &rdev->corrected_errors);
> }
> sectors -= s;
> sect += s;
> - idx ++;
> + off += s << 9;
> }
> set_bit(R1BIO_Uptodate, &r1_bio->state);
> bio->bi_status = 0;
> @@ -2252,14 +2248,12 @@ static void process_checks(struct r1bio *r1_bio)
> struct r1conf *conf = mddev->private;
> int primary;
> int i;
> - int vcnt;
>
> /* Fix variable parts of all bios */
> - vcnt = (r1_bio->sectors + PAGE_SIZE / 512 - 1) >> (PAGE_SHIFT - 9);
> for (i = 0; i < conf->raid_disks * 2; i++) {
> blk_status_t status;
> struct bio *b = r1_bio->bios[i];
> - struct resync_pages *rp = get_resync_pages(b);
> + struct resync_folio *rf = get_resync_folio(b);
> if (b->bi_end_io != end_sync_read)
> continue;
> /* fixup the bio for reuse, but preserve errno */
> @@ -2269,11 +2263,11 @@ static void process_checks(struct r1bio *r1_bio)
> b->bi_iter.bi_sector = r1_bio->sector +
> conf->mirrors[i].rdev->data_offset;
> b->bi_end_io = end_sync_read;
> - rp->raid_bio = r1_bio;
> - b->bi_private = rp;
> + rf->raid_bio = r1_bio;
> + b->bi_private = rf;
>
> /* initialize bvec table again */
> - md_bio_reset_resync_pages(b, rp, r1_bio->sectors << 9);
> + md_bio_reset_resync_folio(b, rf, r1_bio->sectors << 9);
> }
> for (primary = 0; primary < conf->raid_disks * 2; primary++)
> if (r1_bio->bios[primary]->bi_end_io == end_sync_read &&
> @@ -2284,44 +2278,30 @@ static void process_checks(struct r1bio *r1_bio)
> }
> r1_bio->read_disk = primary;
> for (i = 0; i < conf->raid_disks * 2; i++) {
> - int j = 0;
> struct bio *pbio = r1_bio->bios[primary];
> struct bio *sbio = r1_bio->bios[i];
> blk_status_t status = sbio->bi_status;
> - struct page **ppages = get_resync_pages(pbio)->pages;
> - struct page **spages = get_resync_pages(sbio)->pages;
> - struct bio_vec *bi;
> - int page_len[RESYNC_PAGES] = { 0 };
> - struct bvec_iter_all iter_all;
> + struct folio *pfolio = get_resync_folio(pbio)->folio;
> + struct folio *sfolio = get_resync_folio(sbio)->folio;
>
> if (sbio->bi_end_io != end_sync_read)
> continue;
> /* Now we can 'fixup' the error value */
> sbio->bi_status = 0;
>
> - bio_for_each_segment_all(bi, sbio, iter_all)
> - page_len[j++] = bi->bv_len;
> -
> - if (!status) {
> - for (j = vcnt; j-- ; ) {
> - if (memcmp(page_address(ppages[j]),
> - page_address(spages[j]),
> - page_len[j]))
> - break;
> - }
> - } else
> - j = 0;
> - if (j >= 0)
> + if (status || memcmp(folio_address(pfolio),
> + folio_address(sfolio),
> + r1_bio->sectors << 9)) {
> atomic64_add(r1_bio->sectors, &mddev->resync_mismatches);
> - if (j < 0 || (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)
> - && !status)) {
> - /* No need to write to this device. */
> - sbio->bi_end_io = NULL;
> - rdev_dec_pending(conf->mirrors[i].rdev, mddev);
> - continue;
> + if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery)) {
> + bio_copy_data(sbio, pbio);
> + continue;
> + }
The logic is changed here. The original logic:
1. read ok, no mismatch: no bio_copy_data
2. read ok, mismatch, check: no bio_copy_data
3. read ok, mismatch, no check: need bio_copy_data
4. read fail: need bio_copy_data
The 4 is broken.
How about adding a temporary need_write to make logic more clear?
something like:
if (!status) {
int ret = 0;
ret = memcpy(folio_address(pfolio),
folio_address(sfolio),
r1_bio->sectors << 9);
if (ret) {
atomic64_add(r1_bio->sectors, &mddev->resync_mismatches);
if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
need_write = true;
}
} else
need_write = true;
if (need_write)
bio_copy_data(sbio, pbio);
else {
/* No need to write to this device. */
sbio->bi_end_io = NULL;
rdev_dec_pending(conf->mirrors[i].rdev, mddev);
}
> }
>
> - bio_copy_data(sbio, pbio);
> + /* No need to write to this device. */
> + sbio->bi_end_io = NULL;
> + rdev_dec_pending(conf->mirrors[i].rdev, mddev);
> }
> }
>
> @@ -2446,9 +2426,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
> if (rdev &&
> !test_bit(Faulty, &rdev->flags)) {
> atomic_inc(&rdev->nr_pending);
> - r1_sync_page_io(rdev, sect, s,
> - folio_page(conf->tmpfolio, 0),
> - REQ_OP_WRITE);
> + r1_sync_folio_io(rdev, sect, s, 0,
> + conf->tmpfolio, REQ_OP_WRITE);
> rdev_dec_pending(rdev, mddev);
> }
> }
> @@ -2461,9 +2440,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
> if (rdev &&
> !test_bit(Faulty, &rdev->flags)) {
> atomic_inc(&rdev->nr_pending);
> - if (r1_sync_page_io(rdev, sect, s,
> - folio_page(conf->tmpfolio, 0),
> - REQ_OP_READ)) {
> + if (r1_sync_folio_io(rdev, sect, s, 0,
> + conf->tmpfolio, REQ_OP_READ)) {
> atomic_add(s, &rdev->corrected_errors);
> pr_info("md/raid1:%s: read error corrected (%d sectors at %llu on %pg)\n",
> mdname(mddev), s,
> @@ -2799,7 +2777,6 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
> int good_sectors = RESYNC_SECTORS;
> int min_bad = 0; /* number of sectors that are bad in all devices */
> int idx = sector_to_idx(sector_nr);
> - int page_idx = 0;
>
> if (!mempool_initialized(&conf->r1buf_pool))
> if (init_resync(conf))
> @@ -3003,8 +2980,8 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
> nr_sectors = 0;
> sync_blocks = 0;
> do {
> - struct page *page;
> - int len = PAGE_SIZE;
> + struct folio *folio;
> + int len = RESYNC_BLOCK_SIZE;
> if (sector_nr + (len>>9) > max_sector)
> len = (max_sector - sector_nr) << 9;
> if (len == 0)
> @@ -3020,24 +2997,24 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
> }
>
> for (i = 0 ; i < conf->raid_disks * 2; i++) {
> - struct resync_pages *rp;
> + struct resync_folio *rf;
>
> bio = r1_bio->bios[i];
> - rp = get_resync_pages(bio);
> + rf = get_resync_folio(bio);
> if (bio->bi_end_io) {
> - page = resync_fetch_page(rp, page_idx);
> + folio = resync_fetch_folio(rf);
>
> /*
> * won't fail because the vec table is big
> * enough to hold all these pages
> */
The comments above may not be needed anymore. Because there is only
one vec in the bio.
> - __bio_add_page(bio, page, len, 0);
> + bio_add_folio_nofail(bio, folio, len, 0);
> }
> }
> nr_sectors += len>>9;
> sector_nr += len>>9;
> sync_blocks -= (len>>9);
These three lines are not needed anymore.
> - } while (++page_idx < RESYNC_PAGES);
> + } while (0);
>
> r1_bio->sectors = nr_sectors;
>
> diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
> index 09238dc9cde6..c93706806358 100644
> --- a/drivers/md/raid10.c
> +++ b/drivers/md/raid10.c
> @@ -96,11 +96,11 @@ static void end_reshape(struct r10conf *conf);
>
> /*
> * for resync bio, r10bio pointer can be retrieved from the per-bio
> - * 'struct resync_pages'.
> + * 'struct resync_folio'.
> */
> static inline struct r10bio *get_resync_r10bio(struct bio *bio)
> {
> - return get_resync_pages(bio)->raid_bio;
> + return get_resync_folio(bio)->raid_bio;
> }
>
> static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
> @@ -133,8 +133,8 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
> struct r10bio *r10_bio;
> struct bio *bio;
> int j;
> - int nalloc, nalloc_rp;
> - struct resync_pages *rps;
> + int nalloc, nalloc_rf;
> + struct resync_folio *rfs;
>
> r10_bio = r10bio_pool_alloc(gfp_flags, conf);
> if (!r10_bio)
> @@ -148,58 +148,57 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
>
> /* allocate once for all bios */
> if (!conf->have_replacement)
> - nalloc_rp = nalloc;
> + nalloc_rf = nalloc;
> else
> - nalloc_rp = nalloc * 2;
> - rps = kmalloc_array(nalloc_rp, sizeof(struct resync_pages), gfp_flags);
> - if (!rps)
> + nalloc_rf = nalloc * 2;
> + rfs = kmalloc_array(nalloc_rf, sizeof(struct resync_folio), gfp_flags);
> + if (!rfs)
> goto out_free_r10bio;
>
> /*
> * Allocate bios.
> */
> for (j = nalloc ; j-- ; ) {
> - bio = bio_kmalloc(RESYNC_PAGES, gfp_flags);
> + bio = bio_kmalloc(1, gfp_flags);
> if (!bio)
> goto out_free_bio;
> - bio_init_inline(bio, NULL, RESYNC_PAGES, 0);
> + bio_init_inline(bio, NULL, 1, 0);
> r10_bio->devs[j].bio = bio;
> if (!conf->have_replacement)
> continue;
> - bio = bio_kmalloc(RESYNC_PAGES, gfp_flags);
> + bio = bio_kmalloc(1, gfp_flags);
> if (!bio)
> goto out_free_bio;
> - bio_init_inline(bio, NULL, RESYNC_PAGES, 0);
> + bio_init_inline(bio, NULL, 1, 0);
> r10_bio->devs[j].repl_bio = bio;
> }
> /*
> - * Allocate RESYNC_PAGES data pages and attach them
> - * where needed.
> + * Allocate data folio and attach them where needed.
typo error
s/attach them/attach it/g
> */
> for (j = 0; j < nalloc; j++) {
> struct bio *rbio = r10_bio->devs[j].repl_bio;
> - struct resync_pages *rp, *rp_repl;
> + struct resync_folio *rf, *rf_repl;
>
> - rp = &rps[j];
> + rf = &rfs[j];
> if (rbio)
> - rp_repl = &rps[nalloc + j];
> + rf_repl = &rfs[nalloc + j];
>
> bio = r10_bio->devs[j].bio;
>
> if (!j || test_bit(MD_RECOVERY_SYNC,
> &conf->mddev->recovery)) {
> - if (resync_alloc_pages(rp, gfp_flags))
> + if (resync_alloc_folio(rf, gfp_flags))
> goto out_free_pages;
s/out_free_pages/out_free_folio/g
> } else {
> - memcpy(rp, &rps[0], sizeof(*rp));
> - resync_get_all_pages(rp);
> + memcpy(rf, &rfs[0], sizeof(*rf));
> + resync_get_all_folio(rf);
Maybe the name resync_get_folio is better?
> }
>
> - rp->raid_bio = r10_bio;
> - bio->bi_private = rp;
> + rf->raid_bio = r10_bio;
> + bio->bi_private = rf;
> if (rbio) {
> - memcpy(rp_repl, rp, sizeof(*rp));
> - rbio->bi_private = rp_repl;
> + memcpy(rf_repl, rf, sizeof(*rf));
> + rbio->bi_private = rf_repl;
> }
> }
>
> @@ -207,7 +206,7 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
>
> out_free_pages:
> while (--j >= 0)
> - resync_free_pages(&rps[j]);
> + resync_free_folio(&rfs[j]);
>
> j = 0;
> out_free_bio:
> @@ -219,7 +218,7 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
> bio_uninit(r10_bio->devs[j].repl_bio);
> kfree(r10_bio->devs[j].repl_bio);
> }
> - kfree(rps);
> + kfree(rfs);
> out_free_r10bio:
> rbio_pool_free(r10_bio, conf);
> return NULL;
> @@ -230,14 +229,14 @@ static void r10buf_pool_free(void *__r10_bio, void *data)
> struct r10conf *conf = data;
> struct r10bio *r10bio = __r10_bio;
> int j;
> - struct resync_pages *rp = NULL;
> + struct resync_folio *rf = NULL;
>
> for (j = conf->copies; j--; ) {
> struct bio *bio = r10bio->devs[j].bio;
>
> if (bio) {
> - rp = get_resync_pages(bio);
> - resync_free_pages(rp);
> + rf = get_resync_folio(bio);
> + resync_free_folio(rf);
> bio_uninit(bio);
> kfree(bio);
> }
> @@ -250,7 +249,7 @@ static void r10buf_pool_free(void *__r10_bio, void *data)
> }
>
> /* resync pages array stored in the 1st bio's .bi_private */
> - kfree(rp);
> + kfree(rf);
>
> rbio_pool_free(r10bio, conf);
> }
> @@ -2342,8 +2341,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
> struct r10conf *conf = mddev->private;
> int i, first;
> struct bio *tbio, *fbio;
> - int vcnt;
> - struct page **tpages, **fpages;
> + struct folio *tfolio, *ffolio;
>
> atomic_set(&r10_bio->remaining, 1);
>
> @@ -2359,14 +2357,13 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
> fbio = r10_bio->devs[i].bio;
> fbio->bi_iter.bi_size = r10_bio->sectors << 9;
> fbio->bi_iter.bi_idx = 0;
> - fpages = get_resync_pages(fbio)->pages;
> + ffolio = get_resync_folio(fbio)->folio;
>
> - vcnt = (r10_bio->sectors + (PAGE_SIZE >> 9) - 1) >> (PAGE_SHIFT - 9);
> /* now find blocks with errors */
> for (i=0 ; i < conf->copies ; i++) {
> - int j, d;
> + int d;
> struct md_rdev *rdev;
> - struct resync_pages *rp;
> + struct resync_folio *rf;
>
> tbio = r10_bio->devs[i].bio;
>
> @@ -2375,31 +2372,23 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
> if (i == first)
> continue;
>
> - tpages = get_resync_pages(tbio)->pages;
> + tfolio = get_resync_folio(tbio)->folio;
> d = r10_bio->devs[i].devnum;
> rdev = conf->mirrors[d].rdev;
> if (!r10_bio->devs[i].bio->bi_status) {
> /* We know that the bi_io_vec layout is the same for
> * both 'first' and 'i', so we just compare them.
> - * All vec entries are PAGE_SIZE;
> */
> - int sectors = r10_bio->sectors;
> - for (j = 0; j < vcnt; j++) {
> - int len = PAGE_SIZE;
> - if (sectors < (len / 512))
> - len = sectors * 512;
> - if (memcmp(page_address(fpages[j]),
> - page_address(tpages[j]),
> - len))
> - break;
> - sectors -= len/512;
> + if (memcmp(folio_address(ffolio),
> + folio_address(tfolio),
> + r10_bio->sectors << 9)) {
> + atomic64_add(r10_bio->sectors,
> + &mddev->resync_mismatches);
> + if (test_bit(MD_RECOVERY_CHECK,
> + &mddev->recovery))
> + /* Don't fix anything. */
> + continue;
> }
> - if (j == vcnt)
> - continue;
> - atomic64_add(r10_bio->sectors, &mddev->resync_mismatches);
> - if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
> - /* Don't fix anything. */
> - continue;
> } else if (test_bit(FailFast, &rdev->flags)) {
> /* Just give up on this device */
> md_error(rdev->mddev, rdev);
> @@ -2410,13 +2399,13 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
> * First we need to fixup bv_offset, bv_len and
> * bi_vecs, as the read request might have corrupted these
> */
> - rp = get_resync_pages(tbio);
> + rf = get_resync_folio(tbio);
> bio_reset(tbio, conf->mirrors[d].rdev->bdev, REQ_OP_WRITE);
>
> - md_bio_reset_resync_pages(tbio, rp, fbio->bi_iter.bi_size);
> + md_bio_reset_resync_folio(tbio, rf, fbio->bi_iter.bi_size);
>
> - rp->raid_bio = r10_bio;
> - tbio->bi_private = rp;
> + rf->raid_bio = r10_bio;
> + tbio->bi_private = rf;
> tbio->bi_iter.bi_sector = r10_bio->devs[i].addr;
> tbio->bi_end_io = end_sync_write;
>
> @@ -2476,10 +2465,9 @@ static void fix_recovery_read_error(struct r10bio *r10_bio)
> struct bio *bio = r10_bio->devs[0].bio;
> sector_t sect = 0;
> int sectors = r10_bio->sectors;
> - int idx = 0;
> int dr = r10_bio->devs[0].devnum;
> int dw = r10_bio->devs[1].devnum;
> - struct page **pages = get_resync_pages(bio)->pages;
> + struct folio *folio = get_resync_folio(bio)->folio;
>
> while (sectors) {
> int s = sectors;
> @@ -2492,19 +2480,21 @@ static void fix_recovery_read_error(struct r10bio *r10_bio)
>
> rdev = conf->mirrors[dr].rdev;
> addr = r10_bio->devs[0].addr + sect;
> - ok = sync_page_io(rdev,
> - addr,
> - s << 9,
> - pages[idx],
> - REQ_OP_READ, false);
> + ok = sync_folio_io(rdev,
> + addr,
> + s << 9,
> + sect << 9,
> + folio,
> + REQ_OP_READ, false);
By the comments at the beginning of fix_recovery_read_error, it needs
to submit io with a page size unit, right? If so, it still needs to
use sync_page_io here.
> if (ok) {
> rdev = conf->mirrors[dw].rdev;
> addr = r10_bio->devs[1].addr + sect;
> - ok = sync_page_io(rdev,
> - addr,
> - s << 9,
> - pages[idx],
> - REQ_OP_WRITE, false);
> + ok = sync_folio_io(rdev,
> + addr,
> + s << 9,
> + sect << 9,
> + folio,
> + REQ_OP_WRITE, false);
> if (!ok) {
> set_bit(WriteErrorSeen, &rdev->flags);
> if (!test_and_set_bit(WantReplacement,
> @@ -2539,7 +2529,6 @@ static void fix_recovery_read_error(struct r10bio *r10_bio)
>
> sectors -= s;
> sect += s;
> - idx++;
> }
> }
>
> @@ -3174,7 +3163,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
> int max_sync = RESYNC_SECTORS;
> sector_t sync_blocks;
> sector_t chunk_mask = conf->geo.chunk_mask;
> - int page_idx = 0;
>
> /*
> * Allow skipping a full rebuild for incremental assembly
> @@ -3277,7 +3265,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
> * with 2 bios in each, that correspond to the bios in the main one.
> * In this case, the subordinate r10bios link back through a
> * borrowed master_bio pointer, and the counter in the master
> - * includes a ref from each subordinate.
> + * bio_add_folio includes a ref from each subordinate.
What's the reason change this? And I don't understand the new version.
Best Regards
Xiao
> */
> /* First, we decide what to do and set ->bi_end_io
> * To end_sync_read if we want to read, and
> @@ -3642,25 +3630,26 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
> if (sector_nr + max_sync < max_sector)
> max_sector = sector_nr + max_sync;
> do {
> - struct page *page;
> - int len = PAGE_SIZE;
> + int len = RESYNC_BLOCK_SIZE;
> +
> if (sector_nr + (len>>9) > max_sector)
> len = (max_sector - sector_nr) << 9;
> if (len == 0)
> break;
> for (bio= biolist ; bio ; bio=bio->bi_next) {
> - struct resync_pages *rp = get_resync_pages(bio);
> - page = resync_fetch_page(rp, page_idx);
> - if (WARN_ON(!bio_add_page(bio, page, len, 0))) {
> + 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))) {
> bio->bi_status = BLK_STS_RESOURCE;
> bio_endio(bio);
> *skipped = 1;
> - return max_sync;
> + return len;
> }
> }
> nr_sectors += len>>9;
> sector_nr += len>>9;
> - } while (++page_idx < RESYNC_PAGES);
> + } while (0);
> r10_bio->sectors = nr_sectors;
>
> if (mddev_is_clustered(mddev) &&
> @@ -4578,7 +4567,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
> int *skipped)
> {
> /* We simply copy at most one chunk (smallest of old and new)
> - * at a time, possibly less if that exceeds RESYNC_PAGES,
> + * at a time, possibly less if that exceeds RESYNC_BLOCK_SIZE,
> * or we hit a bad block or something.
> * This might mean we pause for normal IO in the middle of
> * a chunk, but that is not a problem as mddev->reshape_position
> @@ -4618,14 +4607,13 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
> struct r10bio *r10_bio;
> sector_t next, safe, last;
> int max_sectors;
> - int nr_sectors;
> int s;
> struct md_rdev *rdev;
> int need_flush = 0;
> struct bio *blist;
> struct bio *bio, *read_bio;
> int sectors_done = 0;
> - struct page **pages;
> + struct folio *folio;
>
> if (sector_nr == 0) {
> /* If restarting in the middle, skip the initial sectors */
> @@ -4741,7 +4729,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
> return sectors_done;
> }
>
> - read_bio = bio_alloc_bioset(rdev->bdev, RESYNC_PAGES, REQ_OP_READ,
> + read_bio = bio_alloc_bioset(rdev->bdev, 1, REQ_OP_READ,
> GFP_KERNEL, &mddev->bio_set);
> read_bio->bi_iter.bi_sector = (r10_bio->devs[r10_bio->read_slot].addr
> + rdev->data_offset);
> @@ -4805,32 +4793,23 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
> blist = b;
> }
>
> - /* Now add as many pages as possible to all of these bios. */
> + /* Now add folio to all of these bios. */
>
> - nr_sectors = 0;
> - pages = get_resync_pages(r10_bio->devs[0].bio)->pages;
> - for (s = 0 ; s < max_sectors; s += PAGE_SIZE >> 9) {
> - struct page *page = pages[s / (PAGE_SIZE >> 9)];
> - int len = (max_sectors - s) << 9;
> - if (len > PAGE_SIZE)
> - len = PAGE_SIZE;
> - for (bio = blist; bio ; bio = bio->bi_next) {
> - if (WARN_ON(!bio_add_page(bio, page, len, 0))) {
> - bio->bi_status = BLK_STS_RESOURCE;
> - bio_endio(bio);
> - return sectors_done;
> - }
> + folio = get_resync_folio(r10_bio->devs[0].bio)->folio;
> + for (bio = blist; bio ; bio = bio->bi_next) {
> + if (WARN_ON(!bio_add_folio(bio, folio, max_sectors, 0))) {
> + bio->bi_status = BLK_STS_RESOURCE;
> + bio_endio(bio);
> + return sectors_done;
> }
> - sector_nr += len >> 9;
> - nr_sectors += len >> 9;
> }
> - r10_bio->sectors = nr_sectors;
> + r10_bio->sectors = max_sectors >> 9;
>
> /* Now submit the read */
> atomic_inc(&r10_bio->remaining);
> read_bio->bi_next = NULL;
> submit_bio_noacct(read_bio);
> - sectors_done += nr_sectors;
> + sectors_done += max_sectors;
> if (sector_nr <= last)
> goto read_more;
>
> @@ -4932,8 +4911,8 @@ static int handle_reshape_read_error(struct mddev *mddev,
> struct r10conf *conf = mddev->private;
> struct r10bio *r10b;
> int slot = 0;
> - int idx = 0;
> - struct page **pages;
> + int sect = 0;
> + struct folio *folio;
>
> r10b = kmalloc(struct_size(r10b, devs, conf->copies), GFP_NOIO);
> if (!r10b) {
> @@ -4941,8 +4920,8 @@ static int handle_reshape_read_error(struct mddev *mddev,
> return -ENOMEM;
> }
>
> - /* reshape IOs share pages from .devs[0].bio */
> - pages = get_resync_pages(r10_bio->devs[0].bio)->pages;
> + /* reshape IOs share folio from .devs[0].bio */
> + folio = get_resync_folio(r10_bio->devs[0].bio)->folio;
>
> r10b->sector = r10_bio->sector;
> __raid10_find_phys(&conf->prev, r10b);
> @@ -4958,19 +4937,19 @@ static int handle_reshape_read_error(struct mddev *mddev,
> while (!success) {
> int d = r10b->devs[slot].devnum;
> struct md_rdev *rdev = conf->mirrors[d].rdev;
> - sector_t addr;
> if (rdev == NULL ||
> test_bit(Faulty, &rdev->flags) ||
> !test_bit(In_sync, &rdev->flags))
> goto failed;
>
> - addr = r10b->devs[slot].addr + idx * PAGE_SIZE;
> atomic_inc(&rdev->nr_pending);
> - success = sync_page_io(rdev,
> - addr,
> - s << 9,
> - pages[idx],
> - REQ_OP_READ, false);
> + success = sync_folio_io(rdev,
> + r10b->devs[slot].addr +
> + sect,
> + s << 9,
> + sect << 9,
> + folio,
> + REQ_OP_READ, false);
> rdev_dec_pending(rdev, mddev);
> if (success)
> break;
> @@ -4989,7 +4968,7 @@ static int handle_reshape_read_error(struct mddev *mddev,
> return -EIO;
> }
> sectors -= s;
> - idx++;
> + sect += s;
> }
> kfree(r10b);
> return 0;
> --
> 2.39.2
>
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH 06/15] md/raid1,raid10: use folio for sync path IO
2026-01-20 15:53 ` Xiao Ni
@ 2026-01-22 2:12 ` Li Nan
2026-01-22 7:01 ` Xiao Ni
0 siblings, 1 reply; 26+ messages in thread
From: Li Nan @ 2026-01-22 2:12 UTC (permalink / raw)
To: Xiao Ni, linan666
Cc: song, yukuai, linux-raid, linux-kernel, yangerkun, yi.zhang
在 2026/1/20 23:53, Xiao Ni 写道:
> On Wed, Dec 17, 2025 at 8:11 PM <linan666@huaweicloud.com> wrote:
>>
>> From: Li Nan <linan122@huawei.com>
>>
>> Convert all IO on the sync path to use folios. Rename page-related
>> identifiers to match folio.
>>
>> Retain some now-unnecessary while and for loops to minimize code
>> changes, clean them up in a subsequent patch.
>>
>> Signed-off-by: Li Nan <linan122@huawei.com >> -static inline int resync_alloc_pages(struct resync_pages *rp,
>> +static inline int resync_alloc_folio(struct resync_folio *rf,
>> gfp_t gfp_flags)
>> {
>> - int i;
>> -
>> - for (i = 0; i < RESYNC_PAGES; i++) {
>> - rp->pages[i] = alloc_page(gfp_flags);
>> - if (!rp->pages[i])
>> - goto out_free;
>> - }
>> + rf->folio = folio_alloc(gfp_flags, get_order(RESYNC_BLOCK_SIZE));
>> + if (!rf->folio)
>> + return -ENOMEM;
>
> Is it ok to add an error log here? Compare with the multipage
> situation, the possibility of failure will be somewhat higher because
> it needs to alloc a contiguous block of physical memory.
>
Hi, Xiao
Thanks for your review.
In patch 15 we fall back to a smaller order if sync folio alloc fails.
After that the alloc usually succeeds, so an error log seems noisy. Should
I add a log before the fallback and keep it in patch 15?
>> -static void md_bio_reset_resync_pages(struct bio *bio, struct resync_pages *rp,
>> +static void md_bio_reset_resync_folio(struct bio *bio, struct resync_folio *rf,
>> int size)
>> {
>> - int idx = 0;
>> -
>> /* initialize bvec table again */
>> do {
>> - struct page *page = resync_fetch_page(rp, idx);
>> - int len = min_t(int, size, PAGE_SIZE);
>> + struct folio *folio = resync_fetch_folio(rf);
>> + int len = min_t(int, size, RESYNC_BLOCK_SIZE);
>>
>> - if (WARN_ON(!bio_add_page(bio, page, len, 0))) {
>> + if (WARN_ON(!bio_add_folio(bio, folio, len, 0))) {
>
> Is it ok to use bio_add_folio(bio, folio, RESYNC_BLOCK_SIZE, 0)
> directly here? It removes `size -= len` below, so it's not useless to
> compare size and RESYNC_BLOCK_SIZE above?
>
Same as the previous one, the size is no longer a fixed value after
patch 15. I think keeping it here gives better compatibility.
>> /*
>> - * Allocate RESYNC_PAGES data pages and attach them to
>> - * the first bio.
>> + * Allocate data folio and attach them to the first bio.
>
> typo error
> s/attach them/attach it/g
>
I will fix it later. Thanks.
>> @@ -2284,44 +2278,30 @@ static void process_checks(struct r1bio *r1_bio)
>> }
>> r1_bio->read_disk = primary;
>> for (i = 0; i < conf->raid_disks * 2; i++) {
>> - int j = 0;
>> struct bio *pbio = r1_bio->bios[primary];
>> struct bio *sbio = r1_bio->bios[i];
>> blk_status_t status = sbio->bi_status;
>> - struct page **ppages = get_resync_pages(pbio)->pages;
>> - struct page **spages = get_resync_pages(sbio)->pages;
>> - struct bio_vec *bi;
>> - int page_len[RESYNC_PAGES] = { 0 };
>> - struct bvec_iter_all iter_all;
>> + struct folio *pfolio = get_resync_folio(pbio)->folio;
>> + struct folio *sfolio = get_resync_folio(sbio)->folio;
>>
>> if (sbio->bi_end_io != end_sync_read)
>> continue;
>> /* Now we can 'fixup' the error value */
>> sbio->bi_status = 0;
>>
>> - bio_for_each_segment_all(bi, sbio, iter_all)
>> - page_len[j++] = bi->bv_len;
>> -
>> - if (!status) {
>> - for (j = vcnt; j-- ; ) {
>> - if (memcmp(page_address(ppages[j]),
>> - page_address(spages[j]),
>> - page_len[j]))
>> - break;
>> - }
>> - } else
>> - j = 0;
>> - if (j >= 0)
>> + if (status || memcmp(folio_address(pfolio),
>> + folio_address(sfolio),
>> + r1_bio->sectors << 9)) {
>> atomic64_add(r1_bio->sectors, &mddev->resync_mismatches);
>> - if (j < 0 || (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)
>> - && !status)) {
>> - /* No need to write to this device. */
>> - sbio->bi_end_io = NULL;
>> - rdev_dec_pending(conf->mirrors[i].rdev, mddev);
>> - continue;
>> + if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery)) {
>> + bio_copy_data(sbio, pbio);
>> + continue;
>> + }
>
> The logic is changed here. The original logic:
> 1. read ok, no mismatch: no bio_copy_data
> 2. read ok, mismatch, check: no bio_copy_data
> 3. read ok, mismatch, no check: need bio_copy_data
> 4. read fail: need bio_copy_data
>
> The 4 is broken.
>
> How about adding a temporary need_write to make logic more clear?
>
> something like:
> if (!status) {
> int ret = 0;
> ret = memcpy(folio_address(pfolio),
> folio_address(sfolio),
> r1_bio->sectors << 9);
> if (ret) {
> atomic64_add(r1_bio->sectors, &mddev->resync_mismatches);
> if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
> need_write = true;
> }
> } else
> need_write = true;
>
> if (need_write)
> bio_copy_data(sbio, pbio);
> else {
> /* No need to write to this device. */
> sbio->bi_end_io = NULL;
> rdev_dec_pending(conf->mirrors[i].rdev, mddev);
> }
>
Nice catch, read failis is indeed broken. I’ll fix it in v2.
>> }
>>
>> - bio_copy_data(sbio, pbio);
>> + /* No need to write to this device. */
>> + sbio->bi_end_io = NULL;
>> + rdev_dec_pending(conf->mirrors[i].rdev, mddev);
>> }
>> }
>> >> @@ -3020,24 +2997,24 @@ static sector_t (struct mddev *mddev, sector_t
sector_nr,
>> }
>>
>> for (i = 0 ; i < conf->raid_disks * 2; i++) {
>> - struct resync_pages *rp;
>> + struct resync_folio *rf;
>>
>> bio = r1_bio->bios[i];
>> - rp = get_resync_pages(bio);
>> + rf = get_resync_folio(bio);
>> if (bio->bi_end_io) {
>> - page = resync_fetch_page(rp, page_idx);
>> + folio = resync_fetch_folio(rf);
>>
>> /*
>> * won't fail because the vec table is big
>> * enough to hold all these pages
>> */
>
> The comments above may not be needed anymore. Because there is only
> one vec in the bio.
>
I will clean it up.
>> - __bio_add_page(bio, page, len, 0);
>> + bio_add_folio_nofail(bio, folio, len, 0);
>> }
>> }
>> nr_sectors += len>>9;
>> sector_nr += len>>9;
>> sync_blocks -= (len>>9);
>
> These three lines are not needed anymore.
>
It is cleaned up in later patches. In this patch I only want minimal
changes, just folio API and naming replacements. Do you think I should move
those cleanups into this patch?
>> /*
>> - * Allocate RESYNC_PAGES data pages and attach them
>> - * where needed.
>> + * Allocate data folio and attach them where needed.
>
> typo error
> s/attach them/attach it/g
>
I will fix it in v2.
>> */
>> for (j = 0; j < nalloc; j++) {
>> struct bio *rbio = r10_bio->devs[j].repl_bio;
>> - struct resync_pages *rp, *rp_repl;
>> + struct resync_folio *rf, *rf_repl;
>>
>> - rp = &rps[j];
>> + rf = &rfs[j];
>> if (rbio)
>> - rp_repl = &rps[nalloc + j];
>> + rf_repl = &rfs[nalloc + j];
>>
>> bio = r10_bio->devs[j].bio;
>>
>> if (!j || test_bit(MD_RECOVERY_SYNC,
>> &conf->mddev->recovery)) {
>> - if (resync_alloc_pages(rp, gfp_flags))
>> + if (resync_alloc_folio(rf, gfp_flags))
>> goto out_free_pages;
>
> s/out_free_pages/out_free_folio/g
>
I will fix it in v2.
>> } else {
>> - memcpy(rp, &rps[0], sizeof(*rp));
>> - resync_get_all_pages(rp);
>> + memcpy(rf, &rfs[0], sizeof(*rf));
>> + resync_get_all_folio(rf);
>
> Maybe the name resync_get_folio is better?
Agree, I will rename it in v2.
>> @@ -2492,19 +2480,21 @@ static void fix_recovery_read_error(struct r10bio *r10_bio)
>>
>> rdev = conf->mirrors[dr].rdev;
>> addr = r10_bio->devs[0].addr + sect;
>> - ok = sync_page_io(rdev,
>> - addr,
>> - s << 9,
>> - pages[idx],
>> - REQ_OP_READ, false);
>> + ok = sync_folio_io(rdev,
>> + addr,
>> + s << 9,
>> + sect << 9,
>> + folio,
>> + REQ_OP_READ, false);
>
> By the comments at the beginning of fix_recovery_read_error, it needs
> to submit io with a page size unit, right? If so, it still needs to
> use sync_page_io here.
>
Here 's' is PAGE_SIZE. We just use a 'page' from folio. In patch 10,
I will change it to use logical block size instead, which should be more
reasonable.
>> /*
>> * Allow skipping a full rebuild for incremental assembly
>> @@ -3277,7 +3265,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
>> * with 2 bios in each, that correspond to the bios in the main one.
>> * In this case, the subordinate r10bios link back through a
>> * borrowed master_bio pointer, and the counter in the master
>> - * includes a ref from each subordinate.
>> + * bio_add_folio includes a ref from each subordinate.
>
> What's the reason change this? And I don't understand the new version.
>
It looks like a typo. I will remove it.
> Best Regards
> Xiao
Thanks again for your careful review.
--
Thanks,
Nan
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH 06/15] md/raid1,raid10: use folio for sync path IO
2026-01-22 2:12 ` Li Nan
@ 2026-01-22 7:01 ` Xiao Ni
0 siblings, 0 replies; 26+ messages in thread
From: Xiao Ni @ 2026-01-22 7:01 UTC (permalink / raw)
To: Li Nan; +Cc: song, yukuai, linux-raid, linux-kernel, yangerkun, yi.zhang
On Thu, Jan 22, 2026 at 10:12 AM Li Nan <linan666@huaweicloud.com> wrote:
>
>
>
> 在 2026/1/20 23:53, Xiao Ni 写道:
> > On Wed, Dec 17, 2025 at 8:11 PM <linan666@huaweicloud.com> wrote:
> >>
> >> From: Li Nan <linan122@huawei.com>
> >>
> >> Convert all IO on the sync path to use folios. Rename page-related
> >> identifiers to match folio.
> >>
> >> Retain some now-unnecessary while and for loops to minimize code
> >> changes, clean them up in a subsequent patch.
> >>
> >> Signed-off-by: Li Nan <linan122@huawei.com >> -static inline int resync_alloc_pages(struct resync_pages *rp,
> >> +static inline int resync_alloc_folio(struct resync_folio *rf,
> >> gfp_t gfp_flags)
> >> {
> >> - int i;
> >> -
> >> - for (i = 0; i < RESYNC_PAGES; i++) {
> >> - rp->pages[i] = alloc_page(gfp_flags);
> >> - if (!rp->pages[i])
> >> - goto out_free;
> >> - }
> >> + rf->folio = folio_alloc(gfp_flags, get_order(RESYNC_BLOCK_SIZE));
> >> + if (!rf->folio)
> >> + return -ENOMEM;
> >
> > Is it ok to add an error log here? Compare with the multipage
> > situation, the possibility of failure will be somewhat higher because
> > it needs to alloc a contiguous block of physical memory.
> >
>
> Hi, Xiao
>
> Thanks for your review.
>
> In patch 15 we fall back to a smaller order if sync folio alloc fails.
> After that the alloc usually succeeds, so an error log seems noisy. Should
> I add a log before the fallback and keep it in patch 15?
Thanks for the explanation. No change is needed here :)
>
> >> -static void md_bio_reset_resync_pages(struct bio *bio, struct resync_pages *rp,
> >> +static void md_bio_reset_resync_folio(struct bio *bio, struct resync_folio *rf,
> >> int size)
> >> {
> >> - int idx = 0;
> >> -
> >> /* initialize bvec table again */
> >> do {
> >> - struct page *page = resync_fetch_page(rp, idx);
> >> - int len = min_t(int, size, PAGE_SIZE);
> >> + struct folio *folio = resync_fetch_folio(rf);
> >> + int len = min_t(int, size, RESYNC_BLOCK_SIZE);
> >>
> >> - if (WARN_ON(!bio_add_page(bio, page, len, 0))) {
> >> + if (WARN_ON(!bio_add_folio(bio, folio, len, 0))) {
> >
> > Is it ok to use bio_add_folio(bio, folio, RESYNC_BLOCK_SIZE, 0)
> > directly here? It removes `size -= len` below, so it's not useless to
> > compare size and RESYNC_BLOCK_SIZE above?
> >
>
> Same as the previous one, the size is no longer a fixed value after
> patch 15. I think keeping it here gives better compatibility.
Thanks for the explanation.
>
> >> /*
> >> - * Allocate RESYNC_PAGES data pages and attach them to
> >> - * the first bio.
> >> + * Allocate data folio and attach them to the first bio.
> >
> > typo error
> > s/attach them/attach it/g
> >
>
> I will fix it later. Thanks.
>
> >> @@ -2284,44 +2278,30 @@ static void process_checks(struct r1bio *r1_bio)
> >> }
> >> r1_bio->read_disk = primary;
> >> for (i = 0; i < conf->raid_disks * 2; i++) {
> >> - int j = 0;
> >> struct bio *pbio = r1_bio->bios[primary];
> >> struct bio *sbio = r1_bio->bios[i];
> >> blk_status_t status = sbio->bi_status;
> >> - struct page **ppages = get_resync_pages(pbio)->pages;
> >> - struct page **spages = get_resync_pages(sbio)->pages;
> >> - struct bio_vec *bi;
> >> - int page_len[RESYNC_PAGES] = { 0 };
> >> - struct bvec_iter_all iter_all;
> >> + struct folio *pfolio = get_resync_folio(pbio)->folio;
> >> + struct folio *sfolio = get_resync_folio(sbio)->folio;
> >>
> >> if (sbio->bi_end_io != end_sync_read)
> >> continue;
> >> /* Now we can 'fixup' the error value */
> >> sbio->bi_status = 0;
> >>
> >> - bio_for_each_segment_all(bi, sbio, iter_all)
> >> - page_len[j++] = bi->bv_len;
> >> -
> >> - if (!status) {
> >> - for (j = vcnt; j-- ; ) {
> >> - if (memcmp(page_address(ppages[j]),
> >> - page_address(spages[j]),
> >> - page_len[j]))
> >> - break;
> >> - }
> >> - } else
> >> - j = 0;
> >> - if (j >= 0)
> >> + if (status || memcmp(folio_address(pfolio),
> >> + folio_address(sfolio),
> >> + r1_bio->sectors << 9)) {
> >> atomic64_add(r1_bio->sectors, &mddev->resync_mismatches);
> >> - if (j < 0 || (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)
> >> - && !status)) {
> >> - /* No need to write to this device. */
> >> - sbio->bi_end_io = NULL;
> >> - rdev_dec_pending(conf->mirrors[i].rdev, mddev);
> >> - continue;
> >> + if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery)) {
> >> + bio_copy_data(sbio, pbio);
> >> + continue;
> >> + }
> >
> > The logic is changed here. The original logic:
> > 1. read ok, no mismatch: no bio_copy_data
> > 2. read ok, mismatch, check: no bio_copy_data
> > 3. read ok, mismatch, no check: need bio_copy_data
> > 4. read fail: need bio_copy_data
> >
> > The 4 is broken.
> >
> > How about adding a temporary need_write to make logic more clear?
> >
> > something like:
> > if (!status) {
> > int ret = 0;
> > ret = memcpy(folio_address(pfolio),
> > folio_address(sfolio),
> > r1_bio->sectors << 9);
> > if (ret) {
> > atomic64_add(r1_bio->sectors, &mddev->resync_mismatches);
> > if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
> > need_write = true;
> > }
> > } else
> > need_write = true;
> >
> > if (need_write)
> > bio_copy_data(sbio, pbio);
> > else {
> > /* No need to write to this device. */
> > sbio->bi_end_io = NULL;
> > rdev_dec_pending(conf->mirrors[i].rdev, mddev);
> > }
> >
>
> Nice catch, read failis is indeed broken. I’ll fix it in v2.
>
> >> }
> >>
> >> - bio_copy_data(sbio, pbio);
> >> + /* No need to write to this device. */
> >> + sbio->bi_end_io = NULL;
> >> + rdev_dec_pending(conf->mirrors[i].rdev, mddev);
> >> }
> >> }
> >> >> @@ -3020,24 +2997,24 @@ static sector_t (struct mddev *mddev, sector_t
> sector_nr,
> >> }
> >>
> >> for (i = 0 ; i < conf->raid_disks * 2; i++) {
> >> - struct resync_pages *rp;
> >> + struct resync_folio *rf;
> >>
> >> bio = r1_bio->bios[i];
> >> - rp = get_resync_pages(bio);
> >> + rf = get_resync_folio(bio);
> >> if (bio->bi_end_io) {
> >> - page = resync_fetch_page(rp, page_idx);
> >> + folio = resync_fetch_folio(rf);
> >>
> >> /*
> >> * won't fail because the vec table is big
> >> * enough to hold all these pages
> >> */
> >
> > The comments above may not be needed anymore. Because there is only
> > one vec in the bio.
> >
>
> I will clean it up.
>
> >> - __bio_add_page(bio, page, len, 0);
> >> + bio_add_folio_nofail(bio, folio, len, 0);
> >> }
> >> }
> >> nr_sectors += len>>9;
> >> sector_nr += len>>9;
> >> sync_blocks -= (len>>9);
> >
> > These three lines are not needed anymore.
> >
>
> It is cleaned up in later patches. In this patch I only want minimal
> changes, just folio API and naming replacements. Do you think I should move
> those cleanups into this patch?
I think it's a better choice. But it really depends on you. I'm ok if
you prefer your patch sequence.
>
>
> >> /*
> >> - * Allocate RESYNC_PAGES data pages and attach them
> >> - * where needed.
> >> + * Allocate data folio and attach them where needed.
> >
> > typo error
> > s/attach them/attach it/g
> >
>
> I will fix it in v2.
>
> >> */
> >> for (j = 0; j < nalloc; j++) {
> >> struct bio *rbio = r10_bio->devs[j].repl_bio;
> >> - struct resync_pages *rp, *rp_repl;
> >> + struct resync_folio *rf, *rf_repl;
> >>
> >> - rp = &rps[j];
> >> + rf = &rfs[j];
> >> if (rbio)
> >> - rp_repl = &rps[nalloc + j];
> >> + rf_repl = &rfs[nalloc + j];
> >>
> >> bio = r10_bio->devs[j].bio;
> >>
> >> if (!j || test_bit(MD_RECOVERY_SYNC,
> >> &conf->mddev->recovery)) {
> >> - if (resync_alloc_pages(rp, gfp_flags))
> >> + if (resync_alloc_folio(rf, gfp_flags))
> >> goto out_free_pages;
> >
> > s/out_free_pages/out_free_folio/g
> >
>
> I will fix it in v2.
>
> >> } else {
> >> - memcpy(rp, &rps[0], sizeof(*rp));
> >> - resync_get_all_pages(rp);
> >> + memcpy(rf, &rfs[0], sizeof(*rf));
> >> + resync_get_all_folio(rf);
> >
> > Maybe the name resync_get_folio is better?
>
> Agree, I will rename it in v2.
>
> >> @@ -2492,19 +2480,21 @@ static void fix_recovery_read_error(struct r10bio *r10_bio)
> >>
> >> rdev = conf->mirrors[dr].rdev;
> >> addr = r10_bio->devs[0].addr + sect;
> >> - ok = sync_page_io(rdev,
> >> - addr,
> >> - s << 9,
> >> - pages[idx],
> >> - REQ_OP_READ, false);
> >> + ok = sync_folio_io(rdev,
> >> + addr,
> >> + s << 9,
> >> + sect << 9,
> >> + folio,
> >> + REQ_OP_READ, false);
> >
> > By the comments at the beginning of fix_recovery_read_error, it needs
> > to submit io with a page size unit, right? If so, it still needs to
> > use sync_page_io here.
> >
>
> Here 's' is PAGE_SIZE. We just use a 'page' from folio. In patch 10,
> I will change it to use logical block size instead, which should be more
> reasonable.
Ok.
>
> >> /*
> >> * Allow skipping a full rebuild for incremental assembly
> >> @@ -3277,7 +3265,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
> >> * with 2 bios in each, that correspond to the bios in the main one.
> >> * In this case, the subordinate r10bios link back through a
> >> * borrowed master_bio pointer, and the counter in the master
> >> - * includes a ref from each subordinate.
> >> + * bio_add_folio includes a ref from each subordinate.
> >
> > What's the reason change this? And I don't understand the new version.
> >
>
> It looks like a typo. I will remove it.
>
> > Best Regards
> > Xiao
>
> Thanks again for your careful review.
You're welcome.
Best Regards
Xiao
>
> --
> Thanks,
> Nan
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH 07/15] md: Clean up folio sync support related code
2025-12-17 11:59 [PATCH 00/15] folio support for sync I/O in RAID linan666
` (5 preceding siblings ...)
2025-12-17 12:00 ` [PATCH 06/15] md/raid1,raid10: use folio for sync path IO linan666
@ 2025-12-17 12:00 ` linan666
2026-01-20 16:01 ` Xiao Ni
2025-12-17 12:00 ` [PATCH 08/15] md/raid1: clean up useless sync_blocks handling in raid1_sync_request linan666
` (7 subsequent siblings)
14 siblings, 1 reply; 26+ messages in thread
From: linan666 @ 2025-12-17 12:00 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, xni, linan666, yangerkun, yi.zhang
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>
---
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 b8f2cc32606f..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_all_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 370bdecf5487..f01bab41da95 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_all_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 c93706806358..a03afa9a6a5b 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_pages;
} else {
memcpy(rf, &rfs[0], sizeof(*rf));
- resync_get_all_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 [flat|nested] 26+ messages in thread* Re: [PATCH 07/15] md: Clean up folio sync support related code
2025-12-17 12:00 ` [PATCH 07/15] md: Clean up folio sync support related code linan666
@ 2026-01-20 16:01 ` Xiao Ni
0 siblings, 0 replies; 26+ messages in thread
From: Xiao Ni @ 2026-01-20 16:01 UTC (permalink / raw)
To: linan666; +Cc: song, yukuai, linux-raid, linux-kernel, yangerkun, yi.zhang
On Wed, Dec 17, 2025 at 8:11 PM <linan666@huaweicloud.com> wrote:
>
> 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>
> ---
> 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 b8f2cc32606f..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_all_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 370bdecf5487..f01bab41da95 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_all_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 c93706806358..a03afa9a6a5b 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_pages;
> } else {
> memcpy(rf, &rfs[0], sizeof(*rf));
> - resync_get_all_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
>
Reviewed-by: Xiao Ni <xni@redhat.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH 08/15] md/raid1: clean up useless sync_blocks handling in raid1_sync_request
2025-12-17 11:59 [PATCH 00/15] folio support for sync I/O in RAID linan666
` (6 preceding siblings ...)
2025-12-17 12:00 ` [PATCH 07/15] md: Clean up folio sync support related code linan666
@ 2025-12-17 12:00 ` linan666
2025-12-17 12:00 ` [PATCH 09/15] md/raid1: fix IO error at logical block size granularity linan666
` (6 subsequent siblings)
14 siblings, 0 replies; 26+ messages in thread
From: linan666 @ 2025-12-17 12:00 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, xni, linan666, yangerkun, yi.zhang
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 f01bab41da95..432ab96ec1cc 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2976,7 +2976,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;
@@ -2984,15 +2983,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;
@@ -3011,7 +3008,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 [flat|nested] 26+ messages in thread* [PATCH 09/15] md/raid1: fix IO error at logical block size granularity
2025-12-17 11:59 [PATCH 00/15] folio support for sync I/O in RAID linan666
` (7 preceding siblings ...)
2025-12-17 12:00 ` [PATCH 08/15] md/raid1: clean up useless sync_blocks handling in raid1_sync_request linan666
@ 2025-12-17 12:00 ` linan666
2025-12-17 12:00 ` [PATCH 10/15] md/raid10: " linan666
` (5 subsequent siblings)
14 siblings, 0 replies; 26+ messages in thread
From: linan666 @ 2025-12-17 12:00 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, xni, linan666, yangerkun, yi.zhang
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 432ab96ec1cc..c1580aea4189 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;
@@ -2379,14 +2377,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 [flat|nested] 26+ messages in thread* [PATCH 10/15] md/raid10: fix IO error at logical block size granularity
2025-12-17 11:59 [PATCH 00/15] folio support for sync I/O in RAID linan666
` (8 preceding siblings ...)
2025-12-17 12:00 ` [PATCH 09/15] md/raid1: fix IO error at logical block size granularity linan666
@ 2025-12-17 12:00 ` linan666
2025-12-17 12:00 ` [PATCH 11/15] md/raid1,raid10: clean up resync_fetch_folio linan666
` (4 subsequent siblings)
14 siblings, 0 replies; 26+ messages in thread
From: linan666 @ 2025-12-17 12:00 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, xni, linan666, yangerkun, yi.zhang
From: Li Nan <linan122@huawei.com>
RAID10 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/raid10.c | 18 +++++-------------
1 file changed, 5 insertions(+), 13 deletions(-)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index a03afa9a6a5b..4beea6ee9dfc 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -2452,7 +2452,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
static void fix_recovery_read_error(struct r10bio *r10_bio)
{
/* We got a read error during recovery.
- * We repeat the read in smaller page-sized sections.
+ * We repeat the read in smaller logical_block_sized sections.
* If a read succeeds, write it to the new device or record
* a bad block if we cannot.
* If a read fails, record a bad block on both old and
@@ -2468,14 +2468,11 @@ static void fix_recovery_read_error(struct r10bio *r10_bio)
struct folio *folio = get_resync_folio(bio)->folio;
while (sectors) {
- int s = sectors;
+ int s = min_t(int, sectors, mddev->logical_block_size >> 9);
struct md_rdev *rdev;
sector_t addr;
int ok;
- if (s > (PAGE_SIZE>>9))
- s = PAGE_SIZE >> 9;
-
rdev = conf->mirrors[dr].rdev;
addr = r10_bio->devs[0].addr + sect;
ok = sync_folio_io(rdev,
@@ -2619,14 +2616,11 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
}
while(sectors) {
- int s = sectors;
+ int s = min_t(int, sectors, mddev->logical_block_size >> 9);
int sl = slot;
int success = 0;
int start;
- if (s > (PAGE_SIZE>>9))
- s = PAGE_SIZE >> 9;
-
do {
d = r10_bio->devs[sl].devnum;
rdev = conf->mirrors[d].rdev;
@@ -4925,16 +4919,14 @@ static int handle_reshape_read_error(struct mddev *mddev,
__raid10_find_phys(&conf->prev, r10b);
while (sectors) {
- int s = sectors;
+ int s = min_t(int, sectors, mddev->logical_block_size >> 9);
int success = 0;
int first_slot = slot;
- if (s > (PAGE_SIZE >> 9))
- s = PAGE_SIZE >> 9;
-
while (!success) {
int d = r10b->devs[slot].devnum;
struct md_rdev *rdev = conf->mirrors[d].rdev;
+
if (rdev == NULL ||
test_bit(Faulty, &rdev->flags) ||
!test_bit(In_sync, &rdev->flags))
--
2.39.2
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH 11/15] md/raid1,raid10: clean up resync_fetch_folio
2025-12-17 11:59 [PATCH 00/15] folio support for sync I/O in RAID linan666
` (9 preceding siblings ...)
2025-12-17 12:00 ` [PATCH 10/15] md/raid10: " linan666
@ 2025-12-17 12:00 ` linan666
2025-12-17 12:00 ` [PATCH 12/15] md: clean up resync_free_folio linan666
` (3 subsequent siblings)
14 siblings, 0 replies; 26+ messages in thread
From: linan666 @ 2025-12-17 12:00 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, xni, linan666, yangerkun, yi.zhang
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 | 2 +-
drivers/md/raid10.c | 3 +--
3 files changed, 3 insertions(+), 9 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 c1580aea4189..cf87f36fb7d8 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2992,7 +2992,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
bio = r1_bio->bios[i];
rf = get_resync_folio(bio);
if (bio->bi_end_io) {
- folio = resync_fetch_folio(rf);
+ folio = rf->folio;
/*
* won't fail because the vec table is big
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 4beea6ee9dfc..5afe270f6941 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 [flat|nested] 26+ messages in thread* [PATCH 12/15] md: clean up resync_free_folio
2025-12-17 11:59 [PATCH 00/15] folio support for sync I/O in RAID linan666
` (10 preceding siblings ...)
2025-12-17 12:00 ` [PATCH 11/15] md/raid1,raid10: clean up resync_fetch_folio linan666
@ 2025-12-17 12:00 ` linan666
2025-12-17 12:00 ` [PATCH 13/15] md/raid1: clean up sync IO size calculation in raid1_sync_request linan666
` (2 subsequent siblings)
14 siblings, 0 replies; 26+ messages in thread
From: linan666 @ 2025-12-17 12:00 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, xni, linan666, yangerkun, yi.zhang
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 cf87f36fb7d8..38f86de45dea 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 5afe270f6941..c3ef2ea38b08 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_pages:
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 [flat|nested] 26+ messages in thread* [PATCH 13/15] md/raid1: clean up sync IO size calculation in raid1_sync_request
2025-12-17 11:59 [PATCH 00/15] folio support for sync I/O in RAID linan666
` (11 preceding siblings ...)
2025-12-17 12:00 ` [PATCH 12/15] md: clean up resync_free_folio linan666
@ 2025-12-17 12:00 ` linan666
2025-12-17 12:00 ` [PATCH 14/15] md/raid10: clean up sync IO size calculation in raid10_sync_request linan666
2025-12-17 12:00 ` [PATCH 15/15] md/raid1,raid10: fall back to smaller order if sync folio alloc fails linan666
14 siblings, 0 replies; 26+ messages in thread
From: linan666 @ 2025-12-17 12:00 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, xni, linan666, yangerkun, yi.zhang
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, 7 insertions(+), 10 deletions(-)
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 38f86de45dea..2be2277d4e7e 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2970,21 +2970,19 @@ 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 {
struct folio *folio;
- 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++) {
struct resync_folio *rf;
@@ -2998,11 +2996,10 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
* won't fail because the vec table is big
* enough to hold all these pages
*/
- bio_add_folio_nofail(bio, folio, len, 0);
+ bio_add_folio_nofail(bio, 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 [flat|nested] 26+ messages in thread* [PATCH 14/15] md/raid10: clean up sync IO size calculation in raid10_sync_request
2025-12-17 11:59 [PATCH 00/15] folio support for sync I/O in RAID linan666
` (12 preceding siblings ...)
2025-12-17 12:00 ` [PATCH 13/15] md/raid1: clean up sync IO size calculation in raid1_sync_request linan666
@ 2025-12-17 12:00 ` linan666
2025-12-17 12:00 ` [PATCH 15/15] md/raid1,raid10: fall back to smaller order if sync folio alloc fails linan666
14 siblings, 0 replies; 26+ messages in thread
From: linan666 @ 2025-12-17 12:00 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, xni, linan666, yangerkun, yi.zhang
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 c3ef2ea38b08..f3e10e20ebb1 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 [flat|nested] 26+ messages in thread* [PATCH 15/15] md/raid1,raid10: fall back to smaller order if sync folio alloc fails
2025-12-17 11:59 [PATCH 00/15] folio support for sync I/O in RAID linan666
` (13 preceding siblings ...)
2025-12-17 12:00 ` [PATCH 14/15] md/raid10: clean up sync IO size calculation in raid10_sync_request linan666
@ 2025-12-17 12:00 ` linan666
14 siblings, 0 replies; 26+ messages in thread
From: linan666 @ 2025-12-17 12:00 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, xni, linan666, yangerkun, yi.zhang
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 2be2277d4e7e..a9af40cda7dd 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;
@@ -2767,7 +2769,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);
@@ -2849,8 +2851,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 f3e10e20ebb1..f0e91090097a 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_pages;
} 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_pages:
@@ -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 [flat|nested] 26+ messages in thread