* Re: [PATCH] md/raid5: add exact old and new llbitmap mapping helpers
From: kernel test robot @ 2026-05-01 18:51 UTC (permalink / raw)
To: Yu Kuai, linux-raid
Cc: llvm, oe-kbuild-all, linux-kernel, Li Nan, Yu Kuai, Cheng Cheng
In-Reply-To: <20260419030942.824195-17-yukuai@fnnas.com>
Hi Yu,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on v7.1-rc1 next-20260430]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Yu-Kuai/md-raid5-add-exact-old-and-new-llbitmap-mapping-helpers/20260421-233709
base: linus/master
patch link: https://lore.kernel.org/r/20260419030942.824195-17-yukuai%40fnnas.com
patch subject: [PATCH] md/raid5: add exact old and new llbitmap mapping helpers
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20260502/202605020242.1lRKHrkP-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260502/202605020242.1lRKHrkP-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605020242.1lRKHrkP-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/md/raid5.c:9065:3: error: field designator 'bitmap_sector_map' does not refer to any field in type 'struct md_personality'; did you mean 'bitmap_sector'?
9065 | .bitmap_sector_map = raid5_bitmap_sector_map,
| ^~~~~~~~~~~~~~~~~
| bitmap_sector
drivers/md/md.h:797:9: note: 'bitmap_sector' declared here
797 | void (*bitmap_sector)(struct mddev *mddev, sector_t *offset,
| ^
>> drivers/md/raid5.c:9065:23: error: incompatible function pointer types initializing 'void (*)(struct mddev *, sector_t *, unsigned long *)' (aka 'void (*)(struct mddev *, unsigned long long *, unsigned long *)') with an expression of type 'void (struct mddev *, sector_t *, unsigned long *, bool)' (aka 'void (struct mddev *, unsigned long long *, unsigned long *, _Bool)') [-Wincompatible-function-pointer-types]
9065 | .bitmap_sector_map = raid5_bitmap_sector_map,
| ^~~~~~~~~~~~~~~~~~~~~~~
drivers/md/raid5.c:9065:23: warning: initializer overrides prior initialization of this subobject [-Winitializer-overrides]
9065 | .bitmap_sector_map = raid5_bitmap_sector_map,
| ^~~~~~~~~~~~~~~~~~~~~~~
drivers/md/raid5.c:9064:19: note: previous initialization is here
9064 | .bitmap_sector = raid5_bitmap_sector,
| ^~~~~~~~~~~~~~~~~~~
>> drivers/md/raid5.c:9066:3: error: field designator 'bitmap_sync_size' does not refer to any field in type 'struct md_personality'
9066 | .bitmap_sync_size = raid5_bitmap_sync_size,
| ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/md/raid5.c:9067:3: error: field designator 'bitmap_array_sectors' does not refer to any field in type 'struct md_personality'
9067 | .bitmap_array_sectors = raid5_bitmap_array_sectors,
| ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/md/raid5.c:9098:3: error: field designator 'bitmap_sector_map' does not refer to any field in type 'struct md_personality'; did you mean 'bitmap_sector'?
9098 | .bitmap_sector_map = raid5_bitmap_sector_map,
| ^~~~~~~~~~~~~~~~~
| bitmap_sector
drivers/md/md.h:797:9: note: 'bitmap_sector' declared here
797 | void (*bitmap_sector)(struct mddev *mddev, sector_t *offset,
| ^
drivers/md/raid5.c:9098:23: error: incompatible function pointer types initializing 'void (*)(struct mddev *, sector_t *, unsigned long *)' (aka 'void (*)(struct mddev *, unsigned long long *, unsigned long *)') with an expression of type 'void (struct mddev *, sector_t *, unsigned long *, bool)' (aka 'void (struct mddev *, unsigned long long *, unsigned long *, _Bool)') [-Wincompatible-function-pointer-types]
9098 | .bitmap_sector_map = raid5_bitmap_sector_map,
| ^~~~~~~~~~~~~~~~~~~~~~~
drivers/md/raid5.c:9098:23: warning: initializer overrides prior initialization of this subobject [-Winitializer-overrides]
9098 | .bitmap_sector_map = raid5_bitmap_sector_map,
| ^~~~~~~~~~~~~~~~~~~~~~~
drivers/md/raid5.c:9097:19: note: previous initialization is here
9097 | .bitmap_sector = raid5_bitmap_sector,
| ^~~~~~~~~~~~~~~~~~~
drivers/md/raid5.c:9099:3: error: field designator 'bitmap_sync_size' does not refer to any field in type 'struct md_personality'
9099 | .bitmap_sync_size = raid5_bitmap_sync_size,
| ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/md/raid5.c:9100:3: error: field designator 'bitmap_array_sectors' does not refer to any field in type 'struct md_personality'
9100 | .bitmap_array_sectors = raid5_bitmap_array_sectors,
| ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/md/raid5.c:9132:3: error: field designator 'bitmap_sector_map' does not refer to any field in type 'struct md_personality'; did you mean 'bitmap_sector'?
9132 | .bitmap_sector_map = raid5_bitmap_sector_map,
| ^~~~~~~~~~~~~~~~~
| bitmap_sector
drivers/md/md.h:797:9: note: 'bitmap_sector' declared here
797 | void (*bitmap_sector)(struct mddev *mddev, sector_t *offset,
| ^
drivers/md/raid5.c:9132:23: error: incompatible function pointer types initializing 'void (*)(struct mddev *, sector_t *, unsigned long *)' (aka 'void (*)(struct mddev *, unsigned long long *, unsigned long *)') with an expression of type 'void (struct mddev *, sector_t *, unsigned long *, bool)' (aka 'void (struct mddev *, unsigned long long *, unsigned long *, _Bool)') [-Wincompatible-function-pointer-types]
9132 | .bitmap_sector_map = raid5_bitmap_sector_map,
| ^~~~~~~~~~~~~~~~~~~~~~~
drivers/md/raid5.c:9132:23: warning: initializer overrides prior initialization of this subobject [-Winitializer-overrides]
9132 | .bitmap_sector_map = raid5_bitmap_sector_map,
| ^~~~~~~~~~~~~~~~~~~~~~~
drivers/md/raid5.c:9131:19: note: previous initialization is here
9131 | .bitmap_sector = raid5_bitmap_sector,
| ^~~~~~~~~~~~~~~~~~~
drivers/md/raid5.c:9133:3: error: field designator 'bitmap_sync_size' does not refer to any field in type 'struct md_personality'
9133 | .bitmap_sync_size = raid5_bitmap_sync_size,
| ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/md/raid5.c:9134:3: error: field designator 'bitmap_array_sectors' does not refer to any field in type 'struct md_personality'
9134 | .bitmap_array_sectors = raid5_bitmap_array_sectors,
| ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 warnings and 12 errors generated.
vim +9065 drivers/md/raid5.c
9035
9036 static struct md_personality raid6_personality =
9037 {
9038 .head = {
9039 .type = MD_PERSONALITY,
9040 .id = ID_RAID6,
9041 .name = "raid6",
9042 .owner = THIS_MODULE,
9043 },
9044
9045 .make_request = raid5_make_request,
9046 .run = raid5_run,
9047 .start = raid5_start,
9048 .free = raid5_free,
9049 .status = raid5_status,
9050 .error_handler = raid5_error,
9051 .hot_add_disk = raid5_add_disk,
9052 .hot_remove_disk= raid5_remove_disk,
9053 .spare_active = raid5_spare_active,
9054 .sync_request = raid5_sync_request,
9055 .resize = raid5_resize,
9056 .size = raid5_size,
9057 .check_reshape = raid6_check_reshape,
9058 .start_reshape = raid5_start_reshape,
9059 .finish_reshape = raid5_finish_reshape,
9060 .quiesce = raid5_quiesce,
9061 .takeover = raid6_takeover,
9062 .change_consistency_policy = raid5_change_consistency_policy,
9063 .prepare_suspend = raid5_prepare_suspend,
9064 .bitmap_sector = raid5_bitmap_sector,
> 9065 .bitmap_sector_map = raid5_bitmap_sector_map,
> 9066 .bitmap_sync_size = raid5_bitmap_sync_size,
> 9067 .bitmap_array_sectors = raid5_bitmap_array_sectors,
9068 };
9069 static struct md_personality raid5_personality =
9070 {
9071 .head = {
9072 .type = MD_PERSONALITY,
9073 .id = ID_RAID5,
9074 .name = "raid5",
9075 .owner = THIS_MODULE,
9076 },
9077
9078 .make_request = raid5_make_request,
9079 .run = raid5_run,
9080 .start = raid5_start,
9081 .free = raid5_free,
9082 .status = raid5_status,
9083 .error_handler = raid5_error,
9084 .hot_add_disk = raid5_add_disk,
9085 .hot_remove_disk= raid5_remove_disk,
9086 .spare_active = raid5_spare_active,
9087 .sync_request = raid5_sync_request,
9088 .resize = raid5_resize,
9089 .size = raid5_size,
9090 .check_reshape = raid5_check_reshape,
9091 .start_reshape = raid5_start_reshape,
9092 .finish_reshape = raid5_finish_reshape,
9093 .quiesce = raid5_quiesce,
9094 .takeover = raid5_takeover,
9095 .change_consistency_policy = raid5_change_consistency_policy,
9096 .prepare_suspend = raid5_prepare_suspend,
9097 .bitmap_sector = raid5_bitmap_sector,
9098 .bitmap_sector_map = raid5_bitmap_sector_map,
9099 .bitmap_sync_size = raid5_bitmap_sync_size,
9100 .bitmap_array_sectors = raid5_bitmap_array_sectors,
9101 };
9102
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [PATCH v2 3/3] md/raid1,raid10: fix bio accounting for split md cloned bios
From: Abd-Alrhman Masalkhi @ 2026-05-01 11:46 UTC (permalink / raw)
To: song, yukuai, xni, neilb, shli
Cc: linux-raid, linux-kernel, Abd-Alrhman Masalkhi
In-Reply-To: <20260501114652.590037-1-abd.masalkhi@gmail.com>
Use md_cloned_bio() to control bio accounting instead of relying
on r1bio_existed in raid1 or the io_accounting flag in raid10.
The previous logic does not reliably reflect whether a bio is an
md cloned bio. When a failed bio is split and resubmitted via
bio_submit_split_bioset() on the error path, this can lead to either
double accounting for md cloned bios, or missing accounting for bios
returned from bio_submit_split_bioset()
Fix this by using md_cloned_bio() to detect md cloned bios and
skip accounting accordingly.
Fixes: bb2a9acefaf9 ("md/raid1: switch to use md_account_bio() for io accounting")
Fixes: 820455238366 ("md/raid10: switch to use md_account_bio() for io accounting")
Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
---
This patch depends on patch 1.
Changes in v2:
- New patch.
---
drivers/md/raid1.c | 2 +-
drivers/md/raid10.c | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index c52ecd38c163..dfaf34141325 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1396,7 +1396,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
}
r1_bio->read_disk = rdisk;
- if (!r1bio_existed) {
+ if (likely(!md_cloned_bio(mddev, bio))) {
md_account_bio(mddev, &bio);
r1_bio->master_bio = bio;
}
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 8c6fc398260e..93af7bbc9005 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1146,7 +1146,7 @@ static bool regular_request_wait(struct mddev *mddev, struct r10conf *conf,
}
static void raid10_read_request(struct mddev *mddev, struct bio *bio,
- struct r10bio *r10_bio, bool io_accounting)
+ struct r10bio *r10_bio)
{
struct r10conf *conf = mddev->private;
struct bio *read_bio;
@@ -1226,7 +1226,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
}
slot = r10_bio->read_slot;
- if (io_accounting) {
+ if (likely(!md_cloned_bio(mddev, bio))) {
md_account_bio(mddev, &bio);
r10_bio->master_bio = bio;
}
@@ -1552,7 +1552,7 @@ static void __make_request(struct mddev *mddev, struct bio *bio, int sectors)
conf->geo.raid_disks);
if (bio_data_dir(bio) == READ)
- raid10_read_request(mddev, bio, r10_bio, true);
+ raid10_read_request(mddev, bio, r10_bio);
else
raid10_write_request(mddev, bio, r10_bio);
}
@@ -2872,7 +2872,7 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)
rdev_dec_pending(rdev, mddev);
r10_bio->state = 0;
- raid10_read_request(mddev, r10_bio->master_bio, r10_bio, false);
+ raid10_read_request(mddev, r10_bio->master_bio, r10_bio);
/*
* allow_barrier after re-submit to ensure no sync io
* can be issued while regular io pending.
--
2.43.0
^ permalink raw reply related
* [PATCH v2 2/3] md/raid1,raid10: fix error-path detection with md_cloned_bio()
From: Abd-Alrhman Masalkhi @ 2026-05-01 11:46 UTC (permalink / raw)
To: song, yukuai, xni, neilb, shli
Cc: linux-raid, linux-kernel, Abd-Alrhman Masalkhi
In-Reply-To: <20260501114652.590037-1-abd.masalkhi@gmail.com>
Detect the error path using md_cloned_bio() instead of relying
on r1_bio in raid1 or r10_bio->read_slot in raid10, which may be
NULL or -1 after splitting and resubmitting a failed bio.
As a result, the error path may not be recognized and memory
allocations can incorrectly use GFP_NOIO instead of
(GFP_NOIO | __GFP_HIGH), which can lead to a deadlock under
memory pressure.
Fixes: 689389a06ce7 ("md/raid1: simplify handle_read_error().")
Fixes: 545250f24809 ("md/raid10: simplify handle_read_error()")
Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
---
This patch depends on patch 1.
Changes in v2:
- New patch.
---
drivers/md/raid1.c | 13 ++++++++++---
drivers/md/raid10.c | 20 ++++++++++++++------
2 files changed, 24 insertions(+), 9 deletions(-)
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index cc9914bd15c1..c52ecd38c163 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1321,11 +1321,18 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
bool r1bio_existed = !!r1_bio;
/*
- * If r1_bio is set, we are blocking the raid1d thread
- * so there is a tiny risk of deadlock. So ask for
+ * An md cloned bio indicates we are in the error path.
+ * This is more reliable than checking r1_bio, which might
+ * be NULL even in the error path if a failed bio was split.
+ */
+ bool err_path = md_cloned_bio(mddev, bio);
+
+ /*
+ * If we are in the error path, we are blocking the raid1d
+ * thread so there is a tiny risk of deadlock. So ask for
* emergency memory if needed.
*/
- gfp_t gfp = r1_bio ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO;
+ gfp_t gfp = err_path ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO;
/*
* Still need barrier for READ in case that whole
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 3a591e60a144..8c6fc398260e 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1155,7 +1155,20 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
char b[BDEVNAME_SIZE];
int slot = r10_bio->read_slot;
struct md_rdev *err_rdev = NULL;
- gfp_t gfp = GFP_NOIO;
+
+ /*
+ * An md cloned bio indicates we are in the error path.
+ * This is more reliable than checking slot, which might
+ * be -1 even in the error path if a failed bio was split.
+ */
+ bool err_path = md_cloned_bio(mddev, bio);
+
+ /*
+ * If we are in the error path, we are blocking the raid10d
+ * thread so there is a tiny risk of deadlock. So ask for
+ * emergency memory if needed.
+ */
+ gfp_t gfp = err_path ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO;
if (slot >= 0 && r10_bio->devs[slot].rdev) {
/*
@@ -1166,11 +1179,6 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
* we lose the device name in error messages.
*/
int disk;
- /*
- * As we are blocking raid10, it is a little safer to
- * use __GFP_HIGH.
- */
- gfp = GFP_NOIO | __GFP_HIGH;
disk = r10_bio->devs[slot].devnum;
err_rdev = conf->mirrors[disk].rdev;
--
2.43.0
^ permalink raw reply related
* [PATCH v2 1/3] md/raid1,raid10: fix deadlock in read error recovery path
From: Abd-Alrhman Masalkhi @ 2026-05-01 11:46 UTC (permalink / raw)
To: song, yukuai, xni, neilb, shli
Cc: linux-raid, linux-kernel, Abd-Alrhman Masalkhi
In-Reply-To: <20260501114652.590037-1-abd.masalkhi@gmail.com>
raid1d and raid10d may resubmit a split md cloned bio while handling
a read error. In this case, resubmitting the bio can lead to a deadlock
if the array is suspended before md_handle_request() acquires an
active_io reference via percpu_ref_tryget_live().
Since the cloned bio already holds an active_io reference,
trying to acquire another reference via percpu_ref_tryget_live()
can lead to a deadlock while the array is suspended.
Fix this by using percpu_ref_get() for md cloned bios.
Fixes: bb2a9acefaf9 ("md/raid1: switch to use md_account_bio() for io accounting")
Fixes: 820455238366 ("md/raid10: switch to use md_account_bio() for io accounting")
Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
---
Changes in v2:
- Use md_cloned_bio() consistently to detect cloned bios.
- Recognize that raid10 has the same issue and fix it in this series
- Allow splitting bios.
- Handle md cloned bios explicitly in md_handle_request()
- Link v1: https://lore.kernel.org/linux-raid/20260427103446.300378-1-abd.masalkhi@gmail.com/
Please let me know if I should add a Suggested-by tag for Yu Kuai,
as the solution approach was suggested during review.
Link to Yu Kuai' email: https://lore.kernel.org/linux-raid/m2lde74dtw.fsf@gmail.com/T/#m714020a38b60fc5f84b9a24f0c46acbe5d7342d6
Thanks
Abd-alrhman
---
drivers/md/md.c | 25 ++++++++++++++++---------
drivers/md/md.h | 5 +++++
2 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index e926aef9ec43..96db1e7850e9 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -396,17 +396,24 @@ static bool is_suspended(struct mddev *mddev, struct bio *bio)
bool md_handle_request(struct mddev *mddev, struct bio *bio)
{
check_suspended:
- if (is_suspended(mddev, bio)) {
- /* Bail out if REQ_NOWAIT is set for the bio */
- if (bio->bi_opf & REQ_NOWAIT) {
- bio_wouldblock_error(bio);
- return true;
+ if (unlikely(md_cloned_bio(mddev, bio))) {
+ /*
+ * This bio is an MD cloned bio and already holds an
+ * active_io reference, so percpu_ref_get() is safe here.
+ */
+ percpu_ref_get(&mddev->active_io);
+ } else {
+ if (is_suspended(mddev, bio)) {
+ /* Bail out if REQ_NOWAIT is set for the bio */
+ if (bio->bi_opf & REQ_NOWAIT) {
+ bio_wouldblock_error(bio);
+ return true;
+ }
+ wait_event(mddev->sb_wait, !is_suspended(mddev, bio));
}
- wait_event(mddev->sb_wait, !is_suspended(mddev, bio));
+ if (!percpu_ref_tryget_live(&mddev->active_io))
+ goto check_suspended;
}
- if (!percpu_ref_tryget_live(&mddev->active_io))
- goto check_suspended;
-
if (!mddev->pers->make_request(mddev, bio)) {
percpu_ref_put(&mddev->active_io);
if (mddev_is_dm(mddev) && mddev->pers->prepare_suspend)
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 3bfbee595156..e44074d30cf9 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -1038,6 +1038,11 @@ void mddev_update_io_opt(struct mddev *mddev, unsigned int nr_stripes);
extern const struct block_device_operations md_fops;
+static inline bool md_cloned_bio(struct mddev *mddev, struct bio *bio)
+{
+ return bio->bi_pool == &mddev->io_clone_set;
+}
+
/*
* MD devices can be used undeneath by DM, in which case ->gendisk is NULL.
*/
--
2.43.0
^ permalink raw reply related
* [PATCH v2 0/3] md/raid1,raid10: fix deadlock and bio accounting in read error path
From: Abd-Alrhman Masalkhi @ 2026-05-01 11:46 UTC (permalink / raw)
To: song, yukuai, xni, neilb, shli
Cc: linux-raid, linux-kernel, Abd-Alrhman Masalkhi
Hi,
This series revisits an issue in the read error recovery path for
raid1 and raid10 when bios are split and resubmitted.
In v1, the approach was to avoid splitting bios in the raid1 thread
to prevent recursion and potential deadlocks. However, this was not
ideal and too restrictive.
As suggested by Yu Kuai, this series instead handles the problem in
md_handle_request() and allows bio splitting.
Link to Yu Kuai' email: https://lore.kernel.org/linux-raid/m2lde74dtw.fsf@gmail.com/T/#m714020a38b60fc5f84b9a24f0c46acbe5d7342d6
This series fixes the above by:
- handling md cloned bios explicitly in md_handle_request()
- using md_cloned_bio() to reliably detect the error path
- fixing bio accounting to avoid double/missing accounting
Changes in v2:
- Split fixes into separate patches for clarity.
- Use md_cloned_bio() consistently to detect cloned bios.
- Recognize that raid10 has the same issue and fix it in this series
- Allow splitting bios.
- Handle md cloned bios explicitly in md_handle_request()
- Link v1: https://lore.kernel.org/linux-raid/20260427103446.300378-1-abd.masalkhi@gmail.com/
Abd-Alrhman Masalkhi (3):
md/raid1,raid10: fix deadlock in read error recovery path
md/raid1,raid10: fix error-path detection with md_cloned_bio()
md/raid1,raid10: fix bio accounting for split md cloned bios
drivers/md/md.c | 25 ++++++++++++++++---------
drivers/md/md.h | 5 +++++
drivers/md/raid1.c | 15 +++++++++++----
drivers/md/raid10.c | 28 ++++++++++++++++++----------
4 files changed, 50 insertions(+), 23 deletions(-)
--
2.43.0
^ permalink raw reply
* Re: [PATCH] md/raid5: split reshape bios before bitmap accounting
From: kernel test robot @ 2026-04-30 19:48 UTC (permalink / raw)
To: Yu Kuai, linux-raid
Cc: oe-kbuild-all, linux-kernel, Li Nan, Yu Kuai, Cheng Cheng
In-Reply-To: <20260419030942.824195-20-yukuai@fnnas.com>
Hi Yu,
kernel test robot noticed the following build warnings:
[auto build test WARNING on linus/master]
[also build test WARNING on song-md/md-next v7.1-rc1 next-20260429]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Yu-Kuai/md-raid5-split-reshape-bios-before-bitmap-accounting/20260425-083941
base: linus/master
patch link: https://lore.kernel.org/r/20260419030942.824195-20-yukuai%40fnnas.com
patch subject: [PATCH] md/raid5: split reshape bios before bitmap accounting
config: arc-randconfig-001 (https://download.01.org/0day-ci/archive/20260501/202605010352.oO1uCwCR-lkp@intel.com/config)
compiler: arc-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260501/202605010352.oO1uCwCR-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605010352.oO1uCwCR-lkp@intel.com/
All warnings (new ones prefixed by >>):
drivers/md/raid5.c: In function 'raid5_make_request':
drivers/md/raid5.c:6126:7: error: implicit declaration of function 'mddev_bio_split_at_reshape_offset' [-Werror=implicit-function-declaration]
bi = mddev_bio_split_at_reshape_offset(mddev, bi, NULL,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/md/raid5.c:6126:5: warning: assignment to 'struct bio *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
bi = mddev_bio_split_at_reshape_offset(mddev, bi, NULL,
^
cc1: some warnings being treated as errors
vim +6126 drivers/md/raid5.c
6083
6084 static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
6085 {
6086 DEFINE_WAIT_FUNC(wait, woken_wake_function);
6087 struct r5conf *conf = mddev->private;
6088 const int rw = bio_data_dir(bi);
6089 struct stripe_request_ctx *ctx;
6090 sector_t logical_sector;
6091 enum stripe_result res;
6092 int s, stripe_cnt;
6093 bool on_wq;
6094
6095 if (unlikely(bi->bi_opf & REQ_PREFLUSH)) {
6096 int ret = log_handle_flush_request(conf, bi);
6097
6098 if (ret == 0)
6099 return true;
6100 if (ret == -ENODEV) {
6101 if (md_flush_request(mddev, bi))
6102 return true;
6103 }
6104 /* ret == -EAGAIN, fallback */
6105 }
6106
6107 md_write_start(mddev, bi);
6108 /*
6109 * If array is degraded, better not do chunk aligned read because
6110 * later we might have to read it again in order to reconstruct
6111 * data on failed drives.
6112 */
6113 if (rw == READ && mddev->degraded == 0 &&
6114 mddev->reshape_position == MaxSector) {
6115 bi = chunk_aligned_read(mddev, bi);
6116 if (!bi)
6117 return true;
6118 }
6119
6120 if (unlikely(bio_op(bi) == REQ_OP_DISCARD)) {
6121 make_discard_request(mddev, bi);
6122 md_write_end(mddev);
6123 return true;
6124 }
6125
> 6126 bi = mddev_bio_split_at_reshape_offset(mddev, bi, NULL,
6127 &conf->bio_split);
6128 if (!bi) {
6129 if (rw == WRITE)
6130 md_write_end(mddev);
6131 return true;
6132 }
6133
6134 logical_sector = bi->bi_iter.bi_sector & ~((sector_t)RAID5_STRIPE_SECTORS(conf)-1);
6135 bi->bi_next = NULL;
6136
6137 ctx = mempool_alloc(conf->ctx_pool, GFP_NOIO);
6138 memset(ctx, 0, conf->ctx_size);
6139 ctx->first_sector = logical_sector;
6140 ctx->last_sector = bio_end_sector(bi);
6141 /*
6142 * if r5l_handle_flush_request() didn't clear REQ_PREFLUSH,
6143 * we need to flush journal device
6144 */
6145 if (unlikely(bi->bi_opf & REQ_PREFLUSH))
6146 ctx->do_flush = true;
6147
6148 stripe_cnt = DIV_ROUND_UP_SECTOR_T(ctx->last_sector - logical_sector,
6149 RAID5_STRIPE_SECTORS(conf));
6150 bitmap_set(ctx->sectors_to_do, 0, stripe_cnt);
6151
6152 pr_debug("raid456: %s, logical %llu to %llu\n", __func__,
6153 bi->bi_iter.bi_sector, ctx->last_sector);
6154
6155 /* Bail out if conflicts with reshape and REQ_NOWAIT is set */
6156 if ((bi->bi_opf & REQ_NOWAIT) &&
6157 get_reshape_loc(mddev, conf, logical_sector) == LOC_INSIDE_RESHAPE) {
6158 bio_wouldblock_error(bi);
6159 if (rw == WRITE)
6160 md_write_end(mddev);
6161 mempool_free(ctx, conf->ctx_pool);
6162 return true;
6163 }
6164 md_account_bio(mddev, &bi);
6165
6166 /*
6167 * Lets start with the stripe with the lowest chunk offset in the first
6168 * chunk. That has the best chances of creating IOs adjacent to
6169 * previous IOs in case of sequential IO and thus creates the most
6170 * sequential IO pattern. We don't bother with the optimization when
6171 * reshaping as the performance benefit is not worth the complexity.
6172 */
6173 if (likely(conf->reshape_progress == MaxSector)) {
6174 logical_sector = raid5_bio_lowest_chunk_sector(conf, bi);
6175 on_wq = false;
6176 } else {
6177 add_wait_queue(&conf->wait_for_reshape, &wait);
6178 on_wq = true;
6179 }
6180 s = (logical_sector - ctx->first_sector) >> RAID5_STRIPE_SHIFT(conf);
6181
6182 while (1) {
6183 res = make_stripe_request(mddev, conf, ctx, logical_sector,
6184 bi);
6185 if (res == STRIPE_FAIL || res == STRIPE_WAIT_RESHAPE)
6186 break;
6187
6188 if (res == STRIPE_RETRY)
6189 continue;
6190
6191 if (res == STRIPE_SCHEDULE_AND_RETRY) {
6192 WARN_ON_ONCE(!on_wq);
6193 /*
6194 * Must release the reference to batch_last before
6195 * scheduling and waiting for work to be done,
6196 * otherwise the batch_last stripe head could prevent
6197 * raid5_activate_delayed() from making progress
6198 * and thus deadlocking.
6199 */
6200 if (ctx->batch_last) {
6201 raid5_release_stripe(ctx->batch_last);
6202 ctx->batch_last = NULL;
6203 }
6204
6205 wait_woken(&wait, TASK_UNINTERRUPTIBLE,
6206 MAX_SCHEDULE_TIMEOUT);
6207 continue;
6208 }
6209
6210 s = find_next_bit_wrap(ctx->sectors_to_do, stripe_cnt, s);
6211 if (s == stripe_cnt)
6212 break;
6213
6214 logical_sector = ctx->first_sector +
6215 (s << RAID5_STRIPE_SHIFT(conf));
6216 }
6217 if (unlikely(on_wq))
6218 remove_wait_queue(&conf->wait_for_reshape, &wait);
6219
6220 if (ctx->batch_last)
6221 raid5_release_stripe(ctx->batch_last);
6222
6223 if (rw == WRITE)
6224 md_write_end(mddev);
6225
6226 mempool_free(ctx, conf->ctx_pool);
6227 if (res == STRIPE_WAIT_RESHAPE) {
6228 md_free_cloned_bio(bi);
6229 return false;
6230 }
6231
6232 bio_endio(bi);
6233 return true;
6234 }
6235
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Why is mdraid not listed sashiko.dev (review by gemini/gemini-3.1-pro-preview)?
From: Paul Menzel @ 2026-04-30 15:12 UTC (permalink / raw)
To: Yu Kuai, Song Liu; +Cc: linux-raid
Dear Kuai, dear Song, dear Linux folks,
Do you know, why this subsystem is not listed on the sashiko.dev [1],
where Google’s gemini/gemini-3.1-pro-preview reviews Linux kernel patches?
Kind regards,
Paul
PS: LKML is listed, so patches sent to linux-kernel@vger.kernel.org are
reviewed, but cannot be filtered according to the subsystem.
[1]: https://sashiko.dev/
^ permalink raw reply
* Re: [PATCH] md/raid5: Fix bio retry on interrupted reshape
From: Nigel Croxon @ 2026-04-30 11:53 UTC (permalink / raw)
To: Paul Menzel; +Cc: song, yukuai, linux-raid
In-Reply-To: <a7e94a16-439e-4b28-bc0b-580e00953473@molgen.mpg.de>
Looks like this was just fixed by Benjamin Marzinski's
commit 418b3e64e4459 md/raid5: Fix UAF on IO across the reshape position
So my patch is not needed anymore.
-Nigel
On 4/29/26 9:07 AM, Paul Menzel wrote:
> Dear Nigel,
>
>
> Thank you for your patch.
>
> Am 29.04.26 um 13:10 schrieb Nigel Croxon:
>> When a bio encounters LOC_INSIDE_RESHAPE during a reshape that is
>> interrupted (stopped or unable to progress), the code sets
>> bi->bi_status = BLK_STS_RESOURCE to signal the block layer for retry.
>> However, bio_endio() is never called, so the block layer never
>> receives the completion notification and the retry never happens.
>>
>> This causes I/O to hang when a filesystem is layered over RAID5 and
>> reshape gets stuck.
>>
>> Fix this by calling bio_endio(bi) before md_free_cloned_bio(bi) so
>> the block layer is properly notified of the BLK_STS_RESOURCE status
>> and can retry the request.
>>
>> Tested stripes and stripe size conversions under load comparing
>> files multiple times during each conversion (i.e. MD reshape) on
>> ext4 after dropping caches degrading the RaidLV each time and
>
> I thought RaidLV misspelled Raid V (Raid 5), so should you resend,
> maybe write it as RAID LV.
>
>> no data corruption.
>>
>> Fixes: https://lwn.net/Articles/757123/
>
> Which paragraph/comment exactly?
>
>> Signed-off-by: Nigel Croxon <ncroxon@redhat.com>
>> ---
>> drivers/md/raid5.c | 1 +
>> 1 file changed, 1 insertion(+)
>>
>> diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
>> index 6e79829c5acb..9a3475429ef4 100644
>> --- a/drivers/md/raid5.c
>> +++ b/drivers/md/raid5.c
>> @@ -6217,6 +6217,7 @@ static bool raid5_make_request(struct mddev
>> *mddev, struct bio * bi)
>>
>> mempool_free(ctx, conf->ctx_pool);
>> if (res == STRIPE_WAIT_RESHAPE) {
>> + bio_endio(bi);
>> md_free_cloned_bio(bi);
>> return false;
>> }
>
> Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
>
>
> Kind regards,
>
> Paul
>
^ permalink raw reply
* Re: Suggest me a cost effective SATA SSD?
From: o1bigtenor @ 2026-04-30 10:48 UTC (permalink / raw)
To: linux-raid
In-Reply-To: <afKLmiyhEe4Om0Nt@mail.bitfolk.com>
On Wed, Apr 29, 2026 at 6:09 PM Andy Smith <andy@strugglers.net> wrote:
>
> Hi,
>
> I've inherited a system with a pair of these:
>
> Model Family: Crucial/Micron Client SSDs
> Device Model: CT4000BX500SSD1
> User Capacity: 4,000,787,030,016 bytes [4.00 TB]
>
> Their write performance is terrible. Struggling to get 20MB/s sequential
> write. Their TBW count is low so it's not an issue of excessive write
> cycles. I've searched around and established they are just really bad
> SSDs. They also don't support SMART self-tests, which seems like a
> really cheap thing to do.
>
> I'm further confident that the problem lies with these SSDs because
> there is a pair of much better SSDs in there and they perform as I would
> expect. However, the use case for this storage is for lower cost so it's
> not an option to just buy more of those.
>
> So, could anyone suggest a decent low end (consumer/prosumer market) SSD
> model that is known to work well without terrible firmware bugs under
> Linux, preferably with power loss protection? Low write endurance is
> fine. Capacity of 4TB ideally.
>
I would suggest that power loss protection be sought using a UPS - - - imo a
better idea.
HTH
^ permalink raw reply
* Re: [PATCH] md/raid5: split reshape bios before bitmap accounting
From: kernel test robot @ 2026-04-30 4:07 UTC (permalink / raw)
To: Yu Kuai, linux-raid
Cc: oe-kbuild-all, linux-kernel, Li Nan, Yu Kuai, Cheng Cheng
In-Reply-To: <20260419030942.824195-20-yukuai@fnnas.com>
Hi Yu,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on v7.1-rc1 next-20260429]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Yu-Kuai/md-raid5-split-reshape-bios-before-bitmap-accounting/20260425-083941
base: linus/master
patch link: https://lore.kernel.org/r/20260419030942.824195-20-yukuai%40fnnas.com
patch subject: [PATCH] md/raid5: split reshape bios before bitmap accounting
config: parisc64-defconfig (https://download.01.org/0day-ci/archive/20260430/202604301127.hkMOIzHM-lkp@intel.com/config)
compiler: hppa64-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260430/202604301127.hkMOIzHM-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604301127.hkMOIzHM-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/md/raid5.c: In function 'raid5_make_request':
>> drivers/md/raid5.c:6126:14: error: implicit declaration of function 'mddev_bio_split_at_reshape_offset' [-Wimplicit-function-declaration]
6126 | bi = mddev_bio_split_at_reshape_offset(mddev, bi, NULL,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/md/raid5.c:6126:12: error: assignment to 'struct bio *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
6126 | bi = mddev_bio_split_at_reshape_offset(mddev, bi, NULL,
| ^
vim +/mddev_bio_split_at_reshape_offset +6126 drivers/md/raid5.c
6083
6084 static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
6085 {
6086 DEFINE_WAIT_FUNC(wait, woken_wake_function);
6087 struct r5conf *conf = mddev->private;
6088 const int rw = bio_data_dir(bi);
6089 struct stripe_request_ctx *ctx;
6090 sector_t logical_sector;
6091 enum stripe_result res;
6092 int s, stripe_cnt;
6093 bool on_wq;
6094
6095 if (unlikely(bi->bi_opf & REQ_PREFLUSH)) {
6096 int ret = log_handle_flush_request(conf, bi);
6097
6098 if (ret == 0)
6099 return true;
6100 if (ret == -ENODEV) {
6101 if (md_flush_request(mddev, bi))
6102 return true;
6103 }
6104 /* ret == -EAGAIN, fallback */
6105 }
6106
6107 md_write_start(mddev, bi);
6108 /*
6109 * If array is degraded, better not do chunk aligned read because
6110 * later we might have to read it again in order to reconstruct
6111 * data on failed drives.
6112 */
6113 if (rw == READ && mddev->degraded == 0 &&
6114 mddev->reshape_position == MaxSector) {
6115 bi = chunk_aligned_read(mddev, bi);
6116 if (!bi)
6117 return true;
6118 }
6119
6120 if (unlikely(bio_op(bi) == REQ_OP_DISCARD)) {
6121 make_discard_request(mddev, bi);
6122 md_write_end(mddev);
6123 return true;
6124 }
6125
> 6126 bi = mddev_bio_split_at_reshape_offset(mddev, bi, NULL,
6127 &conf->bio_split);
6128 if (!bi) {
6129 if (rw == WRITE)
6130 md_write_end(mddev);
6131 return true;
6132 }
6133
6134 logical_sector = bi->bi_iter.bi_sector & ~((sector_t)RAID5_STRIPE_SECTORS(conf)-1);
6135 bi->bi_next = NULL;
6136
6137 ctx = mempool_alloc(conf->ctx_pool, GFP_NOIO);
6138 memset(ctx, 0, conf->ctx_size);
6139 ctx->first_sector = logical_sector;
6140 ctx->last_sector = bio_end_sector(bi);
6141 /*
6142 * if r5l_handle_flush_request() didn't clear REQ_PREFLUSH,
6143 * we need to flush journal device
6144 */
6145 if (unlikely(bi->bi_opf & REQ_PREFLUSH))
6146 ctx->do_flush = true;
6147
6148 stripe_cnt = DIV_ROUND_UP_SECTOR_T(ctx->last_sector - logical_sector,
6149 RAID5_STRIPE_SECTORS(conf));
6150 bitmap_set(ctx->sectors_to_do, 0, stripe_cnt);
6151
6152 pr_debug("raid456: %s, logical %llu to %llu\n", __func__,
6153 bi->bi_iter.bi_sector, ctx->last_sector);
6154
6155 /* Bail out if conflicts with reshape and REQ_NOWAIT is set */
6156 if ((bi->bi_opf & REQ_NOWAIT) &&
6157 get_reshape_loc(mddev, conf, logical_sector) == LOC_INSIDE_RESHAPE) {
6158 bio_wouldblock_error(bi);
6159 if (rw == WRITE)
6160 md_write_end(mddev);
6161 mempool_free(ctx, conf->ctx_pool);
6162 return true;
6163 }
6164 md_account_bio(mddev, &bi);
6165
6166 /*
6167 * Lets start with the stripe with the lowest chunk offset in the first
6168 * chunk. That has the best chances of creating IOs adjacent to
6169 * previous IOs in case of sequential IO and thus creates the most
6170 * sequential IO pattern. We don't bother with the optimization when
6171 * reshaping as the performance benefit is not worth the complexity.
6172 */
6173 if (likely(conf->reshape_progress == MaxSector)) {
6174 logical_sector = raid5_bio_lowest_chunk_sector(conf, bi);
6175 on_wq = false;
6176 } else {
6177 add_wait_queue(&conf->wait_for_reshape, &wait);
6178 on_wq = true;
6179 }
6180 s = (logical_sector - ctx->first_sector) >> RAID5_STRIPE_SHIFT(conf);
6181
6182 while (1) {
6183 res = make_stripe_request(mddev, conf, ctx, logical_sector,
6184 bi);
6185 if (res == STRIPE_FAIL || res == STRIPE_WAIT_RESHAPE)
6186 break;
6187
6188 if (res == STRIPE_RETRY)
6189 continue;
6190
6191 if (res == STRIPE_SCHEDULE_AND_RETRY) {
6192 WARN_ON_ONCE(!on_wq);
6193 /*
6194 * Must release the reference to batch_last before
6195 * scheduling and waiting for work to be done,
6196 * otherwise the batch_last stripe head could prevent
6197 * raid5_activate_delayed() from making progress
6198 * and thus deadlocking.
6199 */
6200 if (ctx->batch_last) {
6201 raid5_release_stripe(ctx->batch_last);
6202 ctx->batch_last = NULL;
6203 }
6204
6205 wait_woken(&wait, TASK_UNINTERRUPTIBLE,
6206 MAX_SCHEDULE_TIMEOUT);
6207 continue;
6208 }
6209
6210 s = find_next_bit_wrap(ctx->sectors_to_do, stripe_cnt, s);
6211 if (s == stripe_cnt)
6212 break;
6213
6214 logical_sector = ctx->first_sector +
6215 (s << RAID5_STRIPE_SHIFT(conf));
6216 }
6217 if (unlikely(on_wq))
6218 remove_wait_queue(&conf->wait_for_reshape, &wait);
6219
6220 if (ctx->batch_last)
6221 raid5_release_stripe(ctx->batch_last);
6222
6223 if (rw == WRITE)
6224 md_write_end(mddev);
6225
6226 mempool_free(ctx, conf->ctx_pool);
6227 if (res == STRIPE_WAIT_RESHAPE) {
6228 md_free_cloned_bio(bi);
6229 return false;
6230 }
6231
6232 bio_endio(bi);
6233 return true;
6234 }
6235
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH 01/28] xor: assert that xor_blocks is not call from interrupt context
From: patchwork-bot+linux-riscv @ 2026-04-30 3:24 UTC (permalink / raw)
To: Christoph Hellwig
Cc: linux-riscv, akpm, richard.henderson, mattst88, linmag7, linux,
catalin.marinas, will, ardb, chenhuacai, kernel, maddy, mpe,
npiggin, chleroy, pjw, palmer, aou, alex, hca, gor, agordeev,
borntraeger, svens, davem, andreas, richard, anton.ivanov,
johannes, tglx, mingo, bp, dave.hansen, x86, hpa, herbert,
dan.j.williams, clm, dsterba, arnd, song, yukuai, linan122, tytso,
Jason, linux-alpha, linux-kernel, linux-arm-kernel, loongarch,
linuxppc-dev, linux-s390, sparclinux, linux-um, linux-crypto,
linux-btrfs, linux-arch, linux-raid
In-Reply-To: <20260327061704.3707577-2-hch@lst.de>
Hello:
This series was applied to riscv/linux.git (fixes)
by Andrew Morton <akpm@linux-foundation.org>:
On Fri, 27 Mar 2026 07:16:33 +0100 you wrote:
> Most of the optimized xor_blocks versions require FPU/vector registers,
> which generally are not supported in interrupt context.
>
> Both callers already are in user context, so enforce this at the highest
> level.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
>
> [...]
Here is the summary with links:
- [01/28] xor: assert that xor_blocks is not call from interrupt context
https://git.kernel.org/riscv/c/d8593b8f9354
- [02/28] arm/xor: remove in_interrupt() handling
https://git.kernel.org/riscv/c/b7ca705758b9
- [03/28] arm64/xor: fix conflicting attributes for xor_block_template
https://git.kernel.org/riscv/c/675a0dd596e7
- [04/28] um/xor: cleanup xor.h
https://git.kernel.org/riscv/c/3ea16a98518a
- [05/28] xor: move to lib/raid/
https://git.kernel.org/riscv/c/9e229025e247
- [06/28] xor: small cleanups
https://git.kernel.org/riscv/c/7c6e6b2b48e8
- [07/28] xor: cleanup registration and probing
https://git.kernel.org/riscv/c/0471415f3fd6
- [08/28] xor: split xor.h
https://git.kernel.org/riscv/c/54e20be48fd4
- [09/28] xor: remove macro abuse for XOR implementation registrations
https://git.kernel.org/riscv/c/35ebc4de1059
- [10/28] xor: move generic implementations out of asm-generic/xor.h
https://git.kernel.org/riscv/c/c46928fdcfa0
- [11/28] alpha: move the XOR code to lib/raid/
https://git.kernel.org/riscv/c/503793b1340e
- [12/28] arm: move the XOR code to lib/raid/
https://git.kernel.org/riscv/c/0d64a24ec0c0
- [13/28] arm64: move the XOR code to lib/raid/
https://git.kernel.org/riscv/c/3786f2ad0095
- [14/28] loongarch: move the XOR code to lib/raid/
https://git.kernel.org/riscv/c/033bee3e4963
- [15/28] powerpc: move the XOR code to lib/raid/
https://git.kernel.org/riscv/c/3f276cece4dd
- [16/28] riscv: move the XOR code to lib/raid/
https://git.kernel.org/riscv/c/5265d55b2146
- [17/28] sparc: move the XOR code to lib/raid/
https://git.kernel.org/riscv/c/7f96362396ee
- [18/28] s390: move the XOR code to lib/raid/
https://git.kernel.org/riscv/c/95c104cc5571
- [19/28] x86: move the XOR code to lib/raid/
https://git.kernel.org/riscv/c/77fd47e57a09
- [20/28] xor: avoid indirect calls for arm64-optimized ops
https://git.kernel.org/riscv/c/352ebd066b62
- [21/28] xor: make xor.ko self-contained in lib/raid/
https://git.kernel.org/riscv/c/e20043b4765c
- [22/28] xor: add a better public API
(no matching commit)
- [23/28] xor: add a better public API
(no matching commit)
- [24/28] async_xor: use xor_gen
https://git.kernel.org/riscv/c/7c12c32b9f73
- [25/28] btrfs: use xor_gen
https://git.kernel.org/riscv/c/0f629e7283ad
- [26/28] xor: pass the entire operation to the low-level ops
https://git.kernel.org/riscv/c/80dcf0a7832a
- [27/28] xor: use static_call for xor_gen
https://git.kernel.org/riscv/c/a21921dd02d3
- [28/28] xor: add a kunit test case
https://git.kernel.org/riscv/c/af53e85ef797
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH] md/raid10: wire llbitmap reshape lifecycle
From: kernel test robot @ 2026-04-30 2:37 UTC (permalink / raw)
To: Yu Kuai, linux-raid
Cc: llvm, oe-kbuild-all, linux-kernel, Li Nan, Yu Kuai, Cheng Cheng
In-Reply-To: <20260419030942.824195-15-yukuai@fnnas.com>
Hi Yu,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on song-md/md-next v7.1-rc1 next-20260429]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Yu-Kuai/md-raid10-wire-llbitmap-reshape-lifecycle/20260423-170302
base: linus/master
patch link: https://lore.kernel.org/r/20260419030942.824195-15-yukuai%40fnnas.com
patch subject: [PATCH] md/raid10: wire llbitmap reshape lifecycle
config: um-randconfig-001-20260430 (https://download.01.org/0day-ci/archive/20260430/202604301028.uutGNSgD-lkp@intel.com/config)
compiler: clang version 23.0.0git (https://github.com/llvm/llvm-project 5bac06718f502014fade905512f1d26d578a18f3)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260430/202604301028.uutGNSgD-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604301028.uutGNSgD-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/md/raid10.c:4370:25: error: no member named 'reshape_can_start' in 'struct bitmap_operations'
4370 | mddev->bitmap_ops->reshape_can_start) {
| ~~~~~~~~~~~~~~~~~ ^
drivers/md/raid10.c:4371:28: error: no member named 'reshape_can_start' in 'struct bitmap_operations'
4371 | ret = mddev->bitmap_ops->reshape_can_start(mddev);
| ~~~~~~~~~~~~~~~~~ ^
>> drivers/md/raid10.c:4689:26: error: no member named 'reshape_mark' in 'struct bitmap_operations'
4689 | mddev->bitmap_ops->reshape_mark &&
| ~~~~~~~~~~~~~~~~~ ^
drivers/md/raid10.c:4691:23: error: no member named 'reshape_mark' in 'struct bitmap_operations'
4691 | mddev->bitmap_ops->reshape_mark(mddev, conf->reshape_safe,
| ~~~~~~~~~~~~~~~~~ ^
drivers/md/raid10.c:4899:25: error: no member named 'reshape_mark' in 'struct bitmap_operations'
4899 | mddev->bitmap_ops->reshape_mark &&
| ~~~~~~~~~~~~~~~~~ ^
drivers/md/raid10.c:4901:22: error: no member named 'reshape_mark' in 'struct bitmap_operations'
4901 | mddev->bitmap_ops->reshape_mark(mddev, conf->reshape_safe,
| ~~~~~~~~~~~~~~~~~ ^
>> drivers/md/raid10.c:5043:37: error: no member named 'reshape_finish' in 'struct bitmap_operations'
5043 | if (llbitmap && mddev->bitmap_ops->reshape_finish)
| ~~~~~~~~~~~~~~~~~ ^
drivers/md/raid10.c:5044:22: error: no member named 'reshape_finish' in 'struct bitmap_operations'
5044 | mddev->bitmap_ops->reshape_finish(mddev);
| ~~~~~~~~~~~~~~~~~ ^
>> drivers/md/raid10.c:5107:3: error: field designator 'bitmap_sync_size' does not refer to any field in type 'struct md_personality'
5107 | .bitmap_sync_size = raid10_bitmap_sync_size,
| ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/md/raid10.c:5108:3: error: field designator 'bitmap_array_sectors' does not refer to any field in type 'struct md_personality'
5108 | .bitmap_array_sectors = raid10_bitmap_sync_size,
| ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10 errors generated.
vim +4370 drivers/md/raid10.c
4345
4346 static int raid10_start_reshape(struct mddev *mddev)
4347 {
4348 /* A 'reshape' has been requested. This commits
4349 * the various 'new' fields and sets MD_RECOVER_RESHAPE
4350 * This also checks if there are enough spares and adds them
4351 * to the array.
4352 * We currently require enough spares to make the final
4353 * array non-degraded. We also require that the difference
4354 * between old and new data_offset - on each device - is
4355 * enough that we never risk over-writing.
4356 */
4357
4358 unsigned long before_length, after_length;
4359 sector_t min_offset_diff = 0;
4360 int first = 1;
4361 struct geom new;
4362 struct r10conf *conf = mddev->private;
4363 struct md_rdev *rdev;
4364 int spares = 0;
4365 int ret;
4366
4367 if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
4368 return -EBUSY;
4369 if (md_bitmap_enabled(mddev, false) &&
> 4370 mddev->bitmap_ops->reshape_can_start) {
4371 ret = mddev->bitmap_ops->reshape_can_start(mddev);
4372 if (ret)
4373 return ret;
4374 }
4375
4376 if (setup_geo(&new, mddev, geo_start) != conf->copies)
4377 return -EINVAL;
4378
4379 before_length = ((1 << conf->prev.chunk_shift) *
4380 conf->prev.far_copies);
4381 after_length = ((1 << conf->geo.chunk_shift) *
4382 conf->geo.far_copies);
4383
4384 rdev_for_each(rdev, mddev) {
4385 if (!test_bit(In_sync, &rdev->flags)
4386 && !test_bit(Faulty, &rdev->flags))
4387 spares++;
4388 if (rdev->raid_disk >= 0) {
4389 long long diff = (rdev->new_data_offset
4390 - rdev->data_offset);
4391 if (!mddev->reshape_backwards)
4392 diff = -diff;
4393 if (diff < 0)
4394 diff = 0;
4395 if (first || diff < min_offset_diff)
4396 min_offset_diff = diff;
4397 first = 0;
4398 }
4399 }
4400
4401 if (max(before_length, after_length) > min_offset_diff)
4402 return -EINVAL;
4403
4404 if (spares < mddev->delta_disks)
4405 return -EINVAL;
4406
4407 conf->offset_diff = min_offset_diff;
4408 spin_lock_irq(&conf->device_lock);
4409 if (conf->mirrors_new) {
4410 memcpy(conf->mirrors_new, conf->mirrors,
4411 sizeof(struct raid10_info)*conf->prev.raid_disks);
4412 smp_mb();
4413 kfree(conf->mirrors_old);
4414 conf->mirrors_old = conf->mirrors;
4415 conf->mirrors = conf->mirrors_new;
4416 conf->mirrors_new = NULL;
4417 }
4418 setup_geo(&conf->geo, mddev, geo_start);
4419 smp_mb();
4420 if (mddev->reshape_backwards) {
4421 sector_t size = raid10_size(mddev, 0, 0);
4422 if (size < mddev->array_sectors) {
4423 spin_unlock_irq(&conf->device_lock);
4424 pr_warn("md/raid10:%s: array size must be reduce before number of disks\n",
4425 mdname(mddev));
4426 return -EINVAL;
4427 }
4428 mddev->resync_max_sectors = size;
4429 conf->reshape_progress = size;
4430 } else
4431 conf->reshape_progress = 0;
4432 conf->reshape_safe = conf->reshape_progress;
4433 spin_unlock_irq(&conf->device_lock);
4434
4435 if (mddev->delta_disks && mddev->bitmap) {
4436 struct mdp_superblock_1 *sb = NULL;
4437 sector_t oldsize, newsize;
4438
4439 oldsize = raid10_size(mddev, 0, 0);
4440 newsize = raid10_size(mddev, 0, conf->geo.raid_disks);
4441
4442 if (!mddev_is_clustered(mddev) &&
4443 md_bitmap_enabled(mddev, false)) {
4444 ret = mddev->bitmap_ops->resize(mddev, newsize, 0);
4445 if (ret)
4446 goto abort;
4447 else
4448 goto out;
4449 }
4450
4451 rdev_for_each(rdev, mddev) {
4452 if (rdev->raid_disk > -1 &&
4453 !test_bit(Faulty, &rdev->flags))
4454 sb = page_address(rdev->sb_page);
4455 }
4456
4457 /*
4458 * some node is already performing reshape, and no need to
4459 * call bitmap_ops->resize again since it should be called when
4460 * receiving BITMAP_RESIZE msg
4461 */
4462 if ((sb && (le32_to_cpu(sb->feature_map) &
4463 MD_FEATURE_RESHAPE_ACTIVE)) || (oldsize == newsize))
4464 goto out;
4465
4466 /* cluster can't be setup without bitmap */
4467 ret = mddev->bitmap_ops->resize(mddev, newsize, 0);
4468 if (ret)
4469 goto abort;
4470
4471 ret = mddev->cluster_ops->resize_bitmaps(mddev, newsize, oldsize);
4472 if (ret) {
4473 mddev->bitmap_ops->resize(mddev, oldsize, 0);
4474 goto abort;
4475 }
4476 }
4477 out:
4478 if (mddev->delta_disks > 0) {
4479 rdev_for_each(rdev, mddev)
4480 if (rdev->raid_disk < 0 &&
4481 !test_bit(Faulty, &rdev->flags)) {
4482 if (raid10_add_disk(mddev, rdev) == 0) {
4483 if (rdev->raid_disk >=
4484 conf->prev.raid_disks)
4485 set_bit(In_sync, &rdev->flags);
4486 else
4487 rdev->recovery_offset = 0;
4488
4489 /* Failure here is OK */
4490 sysfs_link_rdev(mddev, rdev);
4491 }
4492 } else if (rdev->raid_disk >= conf->prev.raid_disks
4493 && !test_bit(Faulty, &rdev->flags)) {
4494 /* This is a spare that was manually added */
4495 set_bit(In_sync, &rdev->flags);
4496 }
4497 }
4498 /* When a reshape changes the number of devices,
4499 * ->degraded is measured against the larger of the
4500 * pre and post numbers.
4501 */
4502 spin_lock_irq(&conf->device_lock);
4503 mddev->degraded = calc_degraded(conf);
4504 spin_unlock_irq(&conf->device_lock);
4505 mddev->raid_disks = conf->geo.raid_disks;
4506 mddev->reshape_position = conf->reshape_progress;
4507 set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
4508
4509 clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
4510 clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
4511 clear_bit(MD_RECOVERY_DONE, &mddev->recovery);
4512 set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
4513 set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
4514 conf->reshape_checkpoint = jiffies;
4515 md_new_event();
4516 return 0;
4517
4518 abort:
4519 mddev->recovery = 0;
4520 spin_lock_irq(&conf->device_lock);
4521 conf->geo = conf->prev;
4522 mddev->raid_disks = conf->geo.raid_disks;
4523 rdev_for_each(rdev, mddev)
4524 rdev->new_data_offset = rdev->data_offset;
4525 smp_wmb();
4526 conf->reshape_progress = MaxSector;
4527 conf->reshape_safe = MaxSector;
4528 mddev->reshape_position = MaxSector;
4529 spin_unlock_irq(&conf->device_lock);
4530 return ret;
4531 }
4532
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v3 8/8] md/raid10: fix IO error at logical block size granularity
From: Xiao Ni @ 2026-04-30 2:23 UTC (permalink / raw)
To: linan666; +Cc: song, yukuai, linux-raid, linux-kernel, yangerkun, yi.zhang
In-Reply-To: <20260416033801.786415-9-linan666@huaweicloud.com>
On Thu, Apr 16, 2026 at 11:51 AM <linan666@huaweicloud.com> wrote:
>
> 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>
> Reviewed-by: Yu Kuai <yukuai@fnnas.com>
> ---
> drivers/md/raid10.c | 17 ++++-------------
> 1 file changed, 4 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
> index 3638e00fe420..5b4ffd23211a 100644
> --- a/drivers/md/raid10.c
> +++ b/drivers/md/raid10.c
> @@ -2454,7 +2454,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
> @@ -2470,14 +2470,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,
> @@ -2621,14 +2618,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;
> @@ -4926,13 +4920,10 @@ 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;
> --
> 2.39.2
>
>
This patch looks good to me.
Reviewed-by: Xiao Ni <xni@redhat.com>
^ permalink raw reply
* Re: [PATCH v3 7/8] md/raid1: fix IO error at logical block size granularity
From: Xiao Ni @ 2026-04-30 2:22 UTC (permalink / raw)
To: linan666; +Cc: song, yukuai, linux-raid, linux-kernel, yangerkun, yi.zhang
In-Reply-To: <20260416033801.786415-8-linan666@huaweicloud.com>
On Thu, Apr 16, 2026 at 11:55 AM <linan666@huaweicloud.com> wrote:
>
> 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>
> Reviewed-by: Yu Kuai <yukuai@fnnas.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 724fd4f2cc3a..de8c964ca11d 100644
> --- a/drivers/md/raid1.c
> +++ b/drivers/md/raid1.c
> @@ -2116,7 +2116,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
> @@ -2147,13 +2147,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
> @@ -2192,7 +2190,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;
> @@ -2390,14 +2388,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
>
>
This patch looks good to me.
Reviewed-by: Xiao Ni <xni@redhat.com>
^ permalink raw reply
* Re: [PATCH v3 6/8] md/raid1,raid10: use folio for sync path IO
From: Xiao Ni @ 2026-04-30 1:54 UTC (permalink / raw)
To: linan666; +Cc: song, yukuai, linux-raid, linux-kernel, yangerkun, yi.zhang
In-Reply-To: <20260416033801.786415-7-linan666@huaweicloud.com>
Hi Nan
On Thu, Apr 16, 2026 at 11:55 AM <linan666@huaweicloud.com> wrote:
>
> From: Li Nan <linan122@huawei.com>
>
> Convert all IO on the sync path to use folios, and rename page-related
> identifiers to match folio.
>
> Since RESYNC_BLOCK_SIZE (64K) has higher allocation failure chance than 4k,
> retry with lower orders to improve allocation reliability. A r1/10_bio may
> have different rf->folio orders, so use minimum order as r1/10_bio sectors
> to prevent exceeding size when adding folio to IO later.
>
> Clean up:
> 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.
> 5. Remove resync_fetch_folio(), access 'rf->folio' directly.
> 6. Remove resync_free_folio(), call folio_put() directly.
> 7. clean up sync IO size calculation in raid1/10_sync_request.
>
> Signed-off-by: Li Nan <linan122@huawei.com>
> ---
> drivers/md/md.c | 2 +-
> drivers/md/raid1-10.c | 80 ++++---------
> drivers/md/raid1.c | 209 +++++++++++++++-------------------
> drivers/md/raid10.c | 254 +++++++++++++++++++++---------------------
> 4 files changed, 240 insertions(+), 305 deletions(-)
>
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index 5e83914d5c14..6554b849ac74 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -9440,7 +9440,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 cda531d0720b..10200b0a3fd2 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)
>
> /* when we get a read error on a read-only array, we redirect to another
> @@ -20,9 +19,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 {
> @@ -36,77 +35,44 @@ static void rbio_pool_free(void *rbio, void *data)
> kfree(rbio);
> }
>
> -static inline int resync_alloc_pages(struct resync_pages *rp,
> - gfp_t gfp_flags)
> +static inline int resync_alloc_folio(struct resync_folio *rf,
> + gfp_t gfp_flags, int *order)
> {
> - int i;
> + struct folio *folio;
>
> - for (i = 0; i < RESYNC_PAGES; i++) {
> - rp->pages[i] = alloc_page(gfp_flags);
> - if (!rp->pages[i])
> - goto out_free;
> - }
> + do {
> + folio = folio_alloc(gfp_flags, *order);
> + if (folio)
> + break;
> + } while (--(*order) > 0);
It has a problem here. If it can't allocate a big page, the sync
request unit will be smaller and sync performance may decrease. This
can happen when the system lacks sufficient continuous memory. This
change looks good to me. I just want to throw this problem out for an
open discussion.
>
> + if (!folio)
> + return -ENOMEM;
> +
> + rf->folio = folio;
> return 0;
> -
> -out_free:
> - while (--i >= 0)
> - put_page(rp->pages[i]);
> - return -ENOMEM;
> -}
> -
> -static inline void resync_free_pages(struct resync_pages *rp)
> -{
> - int i;
> -
> - for (i = 0; i < RESYNC_PAGES; i++)
> - put_page(rp->pages[i]);
> -}
> -
> -static inline void resync_get_all_pages(struct resync_pages *rp)
> -{
> - int i;
> -
> - for (i = 0; i < RESYNC_PAGES; i++)
> - get_page(rp->pages[i]);
> -}
> -
> -static inline struct page *resync_fetch_page(struct resync_pages *rp,
> - unsigned idx)
> -{
> - if (WARN_ON_ONCE(idx >= RESYNC_PAGES))
> - return NULL;
> - return rp->pages[idx];
> }
>
> /*
> - * '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);
> -
> - if (WARN_ON(!bio_add_page(bio, page, len, 0))) {
> - bio->bi_status = BLK_STS_RESOURCE;
> - bio_endio(bio);
> - return;
> - }
> -
> - size -= len;
> - } while (idx++ < RESYNC_PAGES && size > 0);
> + if (WARN_ON(!bio_add_folio(bio, rf->folio,
> + 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 a72abdc37a2d..724fd4f2cc3a 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;
The name need_folio is confusing. Can we keep the same style as the
old version? How about need_folios?
> int j;
> - struct resync_pages *rps;
> + struct resync_folio *rfs;
> + int order = get_order(RESYNC_BLOCK_SIZE);
>
> 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 it 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, &order))
> + goto out_free_folio;
> } else {
> - memcpy(rp, &rps[0], sizeof(*rp));
> - resync_get_all_pages(rp);
> + memcpy(rf, &rfs[0], sizeof(*rf));
> + folio_get(rf->folio);
> }
>
> - rp->raid_bio = r1_bio;
> - bio->bi_private = rp;
> + rf->raid_bio = r1_bio;
> + r1_bio->bios[j]->bi_private = rf;
> }
>
> + r1_bio->sectors = 1 << (order + PAGE_SECTORS_SHIFT);
> r1_bio->master_bio = NULL;
>
> return r1_bio;
>
> -out_free_pages:
> +out_free_folio:
> while (--j >= 0)
> - resync_free_pages(&rps[j]);
> + folio_put(rfs[j].folio);
>
> 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]);
> + folio_put(rf->folio);
> 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,39 @@ 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)
> + /*
> + * Copy data and submit write in two cases:
> + * - IO error (non-zero status)
> + * - Data inconsistency and not a CHECK operation.
> + */
> + if (status) {
> 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);
> + bio_copy_data(sbio, pbio);
> continue;
> + } else if (memcmp(folio_address(pfolio),
> + folio_address(sfolio),
> + r1_bio->sectors << 9)) {
> + atomic64_add(r1_bio->sectors, &mddev->resync_mismatches);
> + 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 +2435,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 +2449,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,
> @@ -2738,15 +2725,15 @@ static int init_resync(struct r1conf *conf)
> 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;
>
> for (i = conf->raid_disks * 2; i--; ) {
> bio = r1bio->bios[i];
> - rps = bio->bi_private;
> + rfs = bio->bi_private;
> bio_reset(bio, NULL, 0);
> - bio->bi_private = rps;
> + bio->bi_private = rfs;
> }
> r1bio->master_bio = NULL;
> return r1bio;
> @@ -2775,10 +2762,9 @@ 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);
> - int page_idx = 0;
>
> if (!mempool_initialized(&conf->r1buf_pool))
> if (init_resync(conf))
> @@ -2858,8 +2844,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;
> @@ -2979,44 +2968,28 @@ 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;
> - sync_blocks = 0;
> do {
> - struct page *page;
> - int len = PAGE_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 (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 (nr_sectors > sync_blocks)
> + nr_sectors = sync_blocks;
>
> for (i = 0 ; i < conf->raid_disks * 2; i++) {
> - struct resync_pages *rp;
> -
> bio = r1_bio->bios[i];
> - rp = get_resync_pages(bio);
> if (bio->bi_end_io) {
> - page = resync_fetch_page(rp, page_idx);
> + struct resync_folio *rf = get_resync_folio(bio);
>
> - /*
> - * 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, rf->folio, nr_sectors << 9, 0);
> }
> }
> - nr_sectors += len>>9;
> - sector_nr += len>>9;
> - sync_blocks -= (len>>9);
> - } while (++page_idx < RESYNC_PAGES);
> + sector_nr += nr_sectors;
> + } while (0);
Now it can handle all pages in one go via a folio. It's strange to
keep while(0) here.
>
> r1_bio->sectors = nr_sectors;
This patch is a little big. Is it better to split this patch here?
>
> diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
> index 26f93040cd13..3638e00fe420 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,9 @@ 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;
> + int order = get_order(RESYNC_BLOCK_SIZE);
>
> r10_bio = r10bio_pool_alloc(gfp_flags, conf);
> if (!r10_bio)
> @@ -148,66 +149,64 @@ 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 it 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];
> -
> - bio = r10_bio->devs[j].bio;
> + rf_repl = &rfs[nalloc + j];
>
> if (!j || test_bit(MD_RECOVERY_SYNC,
> &conf->mddev->recovery)) {
> - if (resync_alloc_pages(rp, gfp_flags))
> - goto out_free_pages;
> + if (resync_alloc_folio(rf, gfp_flags, &order))
> + goto out_free_folio;
> } else {
> - memcpy(rp, &rps[0], sizeof(*rp));
> - resync_get_all_pages(rp);
> + memcpy(rf, &rfs[0], sizeof(*rf));
> + folio_get(rf->folio);
> }
>
> - rp->raid_bio = r10_bio;
> - bio->bi_private = rp;
> + rf->raid_bio = r10_bio;
> + r10_bio->devs[j].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;
> }
> }
>
> + r10_bio->sectors = 1 << (order + PAGE_SECTORS_SHIFT);
> return r10_bio;
>
> -out_free_pages:
> +out_free_folio:
> while (--j >= 0)
> - resync_free_pages(&rps[j]);
> + folio_put(rfs[j].folio);
>
> 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);
> + folio_put(rf->folio);
> 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++;
> }
> }
>
> @@ -3050,7 +3039,7 @@ static int init_resync(struct r10conf *conf)
> 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;
> @@ -3063,14 +3052,14 @@ static struct r10bio *raid10_alloc_init_r10buf(struct r10conf *conf)
>
> for (i = 0; i < nalloc; i++) {
> bio = r10bio->devs[i].bio;
> - rp = bio->bi_private;
> + rf = bio->bi_private;
> bio_reset(bio, NULL, 0);
> - bio->bi_private = rp;
> + bio->bi_private = rf;
> bio = r10bio->devs[i].repl_bio;
> if (bio) {
> - rp = bio->bi_private;
> + rf = bio->bi_private;
> bio_reset(bio, NULL, 0);
> - bio->bi_private = rp;
> + bio->bi_private = rf;
> }
> }
> return r10bio;
> @@ -3156,7 +3145,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
> @@ -3376,6 +3364,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;
> @@ -3527,7 +3524,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;
> @@ -3620,29 +3625,25 @@ 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 {
> - struct page *page;
> - int len = PAGE_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;
> 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);
> +
> + 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 max_sync;
> + return nr_sectors << 9;
> }
> }
> - nr_sectors += len>>9;
> - sector_nr += len>>9;
> - } while (++page_idx < RESYNC_PAGES);
> + sector_nr += nr_sectors;
> + } while (0);
> r10_bio->sectors = nr_sectors;
>
> if (mddev_is_clustered(mddev) &&
> @@ -4560,7 +4561,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
> @@ -4600,14 +4601,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 */
> @@ -4709,7 +4709,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));
>
> @@ -4723,7 +4728,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);
> @@ -4787,32 +4792,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;
In fact, the original codes don't clean up before returning.
bio_add_folio_nofail is used in raid1 and can we use
bio_add_folio_nofail here as well?
> }
> - 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;
>
> @@ -4914,8 +4910,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) {
> @@ -4923,8 +4919,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);
> @@ -4940,19 +4936,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;
> @@ -4971,7 +4967,7 @@ static int handle_reshape_read_error(struct mddev *mddev,
> return -EIO;
> }
> sectors -= s;
> - idx++;
> + sect += s;
> }
> kfree(r10b);
> return 0;
> --
> 2.39.2
>
>
Regards
Xiao
^ permalink raw reply
* Re: [PATCH] md/raid5: split reshape bios before bitmap accounting
From: kernel test robot @ 2026-04-30 0:59 UTC (permalink / raw)
To: Yu Kuai, linux-raid
Cc: llvm, oe-kbuild-all, linux-kernel, Li Nan, Yu Kuai, Cheng Cheng
In-Reply-To: <20260419030942.824195-20-yukuai@fnnas.com>
Hi Yu,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on song-md/md-next v7.1-rc1 next-20260429]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Yu-Kuai/md-raid5-split-reshape-bios-before-bitmap-accounting/20260425-083941
base: linus/master
patch link: https://lore.kernel.org/r/20260419030942.824195-20-yukuai%40fnnas.com
patch subject: [PATCH] md/raid5: split reshape bios before bitmap accounting
config: um-randconfig-001-20260430 (https://download.01.org/0day-ci/archive/20260430/202604300803.nq5tYBQB-lkp@intel.com/config)
compiler: clang version 23.0.0git (https://github.com/llvm/llvm-project 5bac06718f502014fade905512f1d26d578a18f3)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260430/202604300803.nq5tYBQB-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604300803.nq5tYBQB-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/md/raid5.c:4221:7: warning: variable 'qread' set but not used [-Wunused-but-set-variable]
4221 | int qread =0;
| ^
>> drivers/md/raid5.c:6126:7: error: call to undeclared function 'mddev_bio_split_at_reshape_offset'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
6126 | bi = mddev_bio_split_at_reshape_offset(mddev, bi, NULL,
| ^
>> drivers/md/raid5.c:6126:5: error: incompatible integer to pointer conversion assigning to 'struct bio *' from 'int' [-Wint-conversion]
6126 | bi = mddev_bio_split_at_reshape_offset(mddev, bi, NULL,
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6127 | &conf->bio_split);
| ~~~~~~~~~~~~~~~~~
1 warning and 2 errors generated.
vim +/mddev_bio_split_at_reshape_offset +6126 drivers/md/raid5.c
6083
6084 static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
6085 {
6086 DEFINE_WAIT_FUNC(wait, woken_wake_function);
6087 struct r5conf *conf = mddev->private;
6088 const int rw = bio_data_dir(bi);
6089 struct stripe_request_ctx *ctx;
6090 sector_t logical_sector;
6091 enum stripe_result res;
6092 int s, stripe_cnt;
6093 bool on_wq;
6094
6095 if (unlikely(bi->bi_opf & REQ_PREFLUSH)) {
6096 int ret = log_handle_flush_request(conf, bi);
6097
6098 if (ret == 0)
6099 return true;
6100 if (ret == -ENODEV) {
6101 if (md_flush_request(mddev, bi))
6102 return true;
6103 }
6104 /* ret == -EAGAIN, fallback */
6105 }
6106
6107 md_write_start(mddev, bi);
6108 /*
6109 * If array is degraded, better not do chunk aligned read because
6110 * later we might have to read it again in order to reconstruct
6111 * data on failed drives.
6112 */
6113 if (rw == READ && mddev->degraded == 0 &&
6114 mddev->reshape_position == MaxSector) {
6115 bi = chunk_aligned_read(mddev, bi);
6116 if (!bi)
6117 return true;
6118 }
6119
6120 if (unlikely(bio_op(bi) == REQ_OP_DISCARD)) {
6121 make_discard_request(mddev, bi);
6122 md_write_end(mddev);
6123 return true;
6124 }
6125
> 6126 bi = mddev_bio_split_at_reshape_offset(mddev, bi, NULL,
6127 &conf->bio_split);
6128 if (!bi) {
6129 if (rw == WRITE)
6130 md_write_end(mddev);
6131 return true;
6132 }
6133
6134 logical_sector = bi->bi_iter.bi_sector & ~((sector_t)RAID5_STRIPE_SECTORS(conf)-1);
6135 bi->bi_next = NULL;
6136
6137 ctx = mempool_alloc(conf->ctx_pool, GFP_NOIO);
6138 memset(ctx, 0, conf->ctx_size);
6139 ctx->first_sector = logical_sector;
6140 ctx->last_sector = bio_end_sector(bi);
6141 /*
6142 * if r5l_handle_flush_request() didn't clear REQ_PREFLUSH,
6143 * we need to flush journal device
6144 */
6145 if (unlikely(bi->bi_opf & REQ_PREFLUSH))
6146 ctx->do_flush = true;
6147
6148 stripe_cnt = DIV_ROUND_UP_SECTOR_T(ctx->last_sector - logical_sector,
6149 RAID5_STRIPE_SECTORS(conf));
6150 bitmap_set(ctx->sectors_to_do, 0, stripe_cnt);
6151
6152 pr_debug("raid456: %s, logical %llu to %llu\n", __func__,
6153 bi->bi_iter.bi_sector, ctx->last_sector);
6154
6155 /* Bail out if conflicts with reshape and REQ_NOWAIT is set */
6156 if ((bi->bi_opf & REQ_NOWAIT) &&
6157 get_reshape_loc(mddev, conf, logical_sector) == LOC_INSIDE_RESHAPE) {
6158 bio_wouldblock_error(bi);
6159 if (rw == WRITE)
6160 md_write_end(mddev);
6161 mempool_free(ctx, conf->ctx_pool);
6162 return true;
6163 }
6164 md_account_bio(mddev, &bi);
6165
6166 /*
6167 * Lets start with the stripe with the lowest chunk offset in the first
6168 * chunk. That has the best chances of creating IOs adjacent to
6169 * previous IOs in case of sequential IO and thus creates the most
6170 * sequential IO pattern. We don't bother with the optimization when
6171 * reshaping as the performance benefit is not worth the complexity.
6172 */
6173 if (likely(conf->reshape_progress == MaxSector)) {
6174 logical_sector = raid5_bio_lowest_chunk_sector(conf, bi);
6175 on_wq = false;
6176 } else {
6177 add_wait_queue(&conf->wait_for_reshape, &wait);
6178 on_wq = true;
6179 }
6180 s = (logical_sector - ctx->first_sector) >> RAID5_STRIPE_SHIFT(conf);
6181
6182 while (1) {
6183 res = make_stripe_request(mddev, conf, ctx, logical_sector,
6184 bi);
6185 if (res == STRIPE_FAIL || res == STRIPE_WAIT_RESHAPE)
6186 break;
6187
6188 if (res == STRIPE_RETRY)
6189 continue;
6190
6191 if (res == STRIPE_SCHEDULE_AND_RETRY) {
6192 WARN_ON_ONCE(!on_wq);
6193 /*
6194 * Must release the reference to batch_last before
6195 * scheduling and waiting for work to be done,
6196 * otherwise the batch_last stripe head could prevent
6197 * raid5_activate_delayed() from making progress
6198 * and thus deadlocking.
6199 */
6200 if (ctx->batch_last) {
6201 raid5_release_stripe(ctx->batch_last);
6202 ctx->batch_last = NULL;
6203 }
6204
6205 wait_woken(&wait, TASK_UNINTERRUPTIBLE,
6206 MAX_SCHEDULE_TIMEOUT);
6207 continue;
6208 }
6209
6210 s = find_next_bit_wrap(ctx->sectors_to_do, stripe_cnt, s);
6211 if (s == stripe_cnt)
6212 break;
6213
6214 logical_sector = ctx->first_sector +
6215 (s << RAID5_STRIPE_SHIFT(conf));
6216 }
6217 if (unlikely(on_wq))
6218 remove_wait_queue(&conf->wait_for_reshape, &wait);
6219
6220 if (ctx->batch_last)
6221 raid5_release_stripe(ctx->batch_last);
6222
6223 if (rw == WRITE)
6224 md_write_end(mddev);
6225
6226 mempool_free(ctx, conf->ctx_pool);
6227 if (res == STRIPE_WAIT_RESHAPE) {
6228 md_free_cloned_bio(bi);
6229 return false;
6230 }
6231
6232 bio_endio(bi);
6233 return true;
6234 }
6235
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: Suggest me a cost effective SATA SSD?
From: Roman Mamedov @ 2026-04-29 23:20 UTC (permalink / raw)
To: Andy Smith; +Cc: linux-raid
In-Reply-To: <afKLmiyhEe4Om0Nt@mail.bitfolk.com>
On Wed, 29 Apr 2026 22:52:10 +0000
Andy Smith <andy@strugglers.net> wrote:
> Model Family: Crucial/Micron Client SSDs
> Device Model: CT4000BX500SSD1
> User Capacity: 4,000,787,030,016 bytes [4.00 TB]
>
> Their write performance is terrible. Struggling to get 20MB/s sequential
> write. Their TBW count is low so it's not an issue of excessive write
> cycles. I've searched around and established they are just really bad
> SSDs. They also don't support SMART self-tests, which seems like a
> really cheap thing to do.
>
> I'm further confident that the problem lies with these SSDs because
> there is a pair of much better SSDs in there and they perform as I would
> expect. However, the use case for this storage is for lower cost so it's
> not an option to just buy more of those.
>
> So, could anyone suggest a decent low end (consumer/prosumer market) SSD
> model that is known to work well without terrible firmware bugs under
> Linux, preferably with power loss protection? Low write endurance is
> fine. Capacity of 4TB ideally.
Basically the main thing to avoid is QLC flash, and look for TLC instead.
Low write speeds and low endurance are all due to the QLC, which prioritizes
capacity and low cost in favor of performance and reliability.
Consult the SSD database at https://www.techpowerup.com/ssd-specs/ about your
potential choices that you see in shops, for what flash type they have.
Or conversely, filter by TLC: https://www.techpowerup.com/ssd-specs/?type=TLC
and then add search term of your favorite vendor to look for candidates to buy.
Keep in mind this info may not be 100% reliable, as it is crowd-sourced and
way too often hidden by the manufacturers, or flash type is switched back and
forth even within the same model.
Side note, I would not count on SMART self tests as being relevant on an SSD.
Sure, on HDD they can scan the entire surface looking for unreadable areas. On
SSDs, what they could do? Read out the entire flash? From the duration of even
the extended offline tests on SSD, they are not doing that. It is opaque and
proprietary as to what they actually do, if anything.
--
With respect,
Roman
^ permalink raw reply
* Suggest me a cost effective SATA SSD?
From: Andy Smith @ 2026-04-29 22:52 UTC (permalink / raw)
To: linux-raid
Hi,
I've inherited a system with a pair of these:
Model Family: Crucial/Micron Client SSDs
Device Model: CT4000BX500SSD1
User Capacity: 4,000,787,030,016 bytes [4.00 TB]
Their write performance is terrible. Struggling to get 20MB/s sequential
write. Their TBW count is low so it's not an issue of excessive write
cycles. I've searched around and established they are just really bad
SSDs. They also don't support SMART self-tests, which seems like a
really cheap thing to do.
I'm further confident that the problem lies with these SSDs because
there is a pair of much better SSDs in there and they perform as I would
expect. However, the use case for this storage is for lower cost so it's
not an option to just buy more of those.
So, could anyone suggest a decent low end (consumer/prosumer market) SSD
model that is known to work well without terrible firmware bugs under
Linux, preferably with power loss protection? Low write endurance is
fine. Capacity of 4TB ideally.
Thanks,
Andy
^ permalink raw reply
* Re: [PATCH] md/raid5: Fix bio retry on interrupted reshape
From: Paul Menzel @ 2026-04-29 13:07 UTC (permalink / raw)
To: Nigel Croxon; +Cc: song, yukuai, linux-raid
In-Reply-To: <f861791b-d539-45ce-8575-5ec74d58d15d@redhat.com>
Dear Nigel,
Thank you for your patch.
Am 29.04.26 um 13:10 schrieb Nigel Croxon:
> When a bio encounters LOC_INSIDE_RESHAPE during a reshape that is
> interrupted (stopped or unable to progress), the code sets
> bi->bi_status = BLK_STS_RESOURCE to signal the block layer for retry.
> However, bio_endio() is never called, so the block layer never
> receives the completion notification and the retry never happens.
>
> This causes I/O to hang when a filesystem is layered over RAID5 and
> reshape gets stuck.
>
> Fix this by calling bio_endio(bi) before md_free_cloned_bio(bi) so
> the block layer is properly notified of the BLK_STS_RESOURCE status
> and can retry the request.
>
> Tested stripes and stripe size conversions under load comparing
> files multiple times during each conversion (i.e. MD reshape) on
> ext4 after dropping caches degrading the RaidLV each time and
I thought RaidLV misspelled Raid V (Raid 5), so should you resend, maybe
write it as RAID LV.
> no data corruption.
>
> Fixes: https://lwn.net/Articles/757123/
Which paragraph/comment exactly?
> Signed-off-by: Nigel Croxon <ncroxon@redhat.com>
> ---
> drivers/md/raid5.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
> index 6e79829c5acb..9a3475429ef4 100644
> --- a/drivers/md/raid5.c
> +++ b/drivers/md/raid5.c
> @@ -6217,6 +6217,7 @@ static bool raid5_make_request(struct mddev
> *mddev, struct bio * bi)
>
> mempool_free(ctx, conf->ctx_pool);
> if (res == STRIPE_WAIT_RESHAPE) {
> + bio_endio(bi);
> md_free_cloned_bio(bi);
> return false;
> }
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Kind regards,
Paul
^ permalink raw reply
* [PATCH] md/raid5: Fix bio retry on interrupted reshape
From: Nigel Croxon @ 2026-04-29 11:10 UTC (permalink / raw)
To: song, yukuai, linux-raid
When a bio encounters LOC_INSIDE_RESHAPE during a reshape that is
interrupted (stopped or unable to progress), the code sets
bi->bi_status = BLK_STS_RESOURCE to signal the block layer for retry.
However, bio_endio() is never called, so the block layer never
receives the completion notification and the retry never happens.
This causes I/O to hang when a filesystem is layered over RAID5 and
reshape gets stuck.
Fix this by calling bio_endio(bi) before md_free_cloned_bio(bi) so
the block layer is properly notified of the BLK_STS_RESOURCE status
and can retry the request.
Tested stripes and stripe size conversions under load comparing
files multiple times during each conversion (i.e. MD reshape) on
ext4 after dropping caches degrading the RaidLV each time and
no data corruption.
Fixes: https://lwn.net/Articles/757123/
Signed-off-by: Nigel Croxon <ncroxon@redhat.com>
---
drivers/md/raid5.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 6e79829c5acb..9a3475429ef4 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -6217,6 +6217,7 @@ static bool raid5_make_request(struct mddev
*mddev, struct bio * bi)
mempool_free(ctx, conf->ctx_pool);
if (res == STRIPE_WAIT_RESHAPE) {
+ bio_endio(bi);
md_free_cloned_bio(bi);
return false;
}
--
2.47.3
^ permalink raw reply related
* [PATCH v2] dm-raid: only requeue bios when dm is suspending.
From: Benjamin Marzinski @ 2026-04-28 23:20 UTC (permalink / raw)
To: Yu Kuai, Song Liu
Cc: linux-raid, dm-devel, Yang Xiuwei, Xiao Ni, Li Nan, Nigel Croxon
returning DM_MAPIO_REQUEUE from the target map() function only requeues
the bio during noflush suspends. During regular operations or during
flushing suspends, it fails the bio. Failing the bio during flushing
suspends is the correct behavior here. We cannot handle the bio, and we
cannot suspends while it is outstanding. But during normal operations,
we should not push the bio back to dm. Instead, wait for the reshape
to be resumed.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
Changes from v1:
- Track the dm device's suspending state in mddev->flags instead of
adding a new integer to mddev.
drivers/md/dm-raid.c | 6 ++++++
drivers/md/md.h | 2 ++
drivers/md/raid5.c | 7 +++++--
3 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index c5dc083c7244..8f5a5e1342a9 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -3831,6 +3831,7 @@ static void raid_presuspend(struct dm_target *ti)
* resume, raid_postsuspend() is too late.
*/
set_bit(RT_FLAG_RS_FROZEN, &rs->runtime_flags);
+ set_bit(MD_DM_SUSPENDING, &mddev->flags);
if (!reshape_interrupted(mddev))
return;
@@ -3847,13 +3848,16 @@ static void raid_presuspend(struct dm_target *ti)
static void raid_presuspend_undo(struct dm_target *ti)
{
struct raid_set *rs = ti->private;
+ struct mddev *mddev = &rs->md;
+ clear_bit(MD_DM_SUSPENDING, &mddev->flags);
clear_bit(RT_FLAG_RS_FROZEN, &rs->runtime_flags);
}
static void raid_postsuspend(struct dm_target *ti)
{
struct raid_set *rs = ti->private;
+ struct mddev *mddev = &rs->md;
if (!test_and_set_bit(RT_FLAG_RS_SUSPENDED, &rs->runtime_flags)) {
/*
@@ -3864,6 +3868,8 @@ static void raid_postsuspend(struct dm_target *ti)
mddev_suspend(&rs->md, false);
rs->md.ro = MD_RDONLY;
}
+ clear_bit(MD_DM_SUSPENDING, &mddev->flags);
+
}
static void attempt_restore_of_faulty_devices(struct raid_set *rs)
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 52c378086046..9e5100609d12 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -346,6 +346,7 @@ struct md_cluster_operations;
* @MD_HAS_SUPERBLOCK: There is persistence sb in member disks.
* @MD_FAILLAST_DEV: Allow last rdev to be removed.
* @MD_SERIALIZE_POLICY: Enforce write IO is not reordered, just used by raid1.
+ * @MD_DM_SUSPENDING: This DM raid device is suspending.
*
* change UNSUPPORTED_MDDEV_FLAGS for each array type if new flag is added
*/
@@ -365,6 +366,7 @@ enum mddev_flags {
MD_HAS_SUPERBLOCK,
MD_FAILLAST_DEV,
MD_SERIALIZE_POLICY,
+ MD_DM_SUSPENDING,
};
enum mddev_sb_flags {
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 0d76e82f4506..65ae7d8930fc 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -6042,8 +6042,11 @@ static enum stripe_result make_stripe_request(struct mddev *mddev,
raid5_release_stripe(sh);
out:
if (ret == STRIPE_SCHEDULE_AND_RETRY && reshape_interrupted(mddev)) {
- bi->bi_status = BLK_STS_RESOURCE;
- ret = STRIPE_WAIT_RESHAPE;
+ if (!mddev_is_dm(mddev) ||
+ test_bit(MD_DM_SUSPENDING, &mddev->flags)) {
+ bi->bi_status = BLK_STS_RESOURCE;
+ ret = STRIPE_WAIT_RESHAPE;
+ }
pr_err_ratelimited("dm-raid456: io across reshape position while reshape can't make progress");
}
return ret;
--
2.53.0
^ permalink raw reply related
* Re: [GIT PULL] md-7.1-20260428
From: Jens Axboe @ 2026-04-28 14:41 UTC (permalink / raw)
To: Yu Kuai
Cc: linux-block, linux-raid, Song Liu, Li Nan, Xiao Ni,
Abd-Alrhman Masalkhi, Benjamin Marzinski, Junrui Luo, Keith Busch
In-Reply-To: <20260428143340.1088943-1-yukuai@fnnas.com>
On 4/28/26 8:33 AM, Yu Kuai wrote:
> Hi Jens,
>
> Please consider pulling the following changes into your block-7.1
> branch.
>
> This pull request contains:
>
> Bug Fixes:
> - Fix a raid5 UAF on IO across the reshape position.
> - Avoid failing RAID1/RAID10 devices for invalid IO errors.
> - Fix RAID10 divide-by-zero when far_copies is zero.
> - Restore bitmap grow through sysfs.
>
> Cleanups:
> - Use mddev_is_dm() instead of open-coding gendisk checks.
> - Use ATTRIBUTE_GROUPS() for md default sysfs attributes.
> - Replace open-coded wait loops with wait_event helpers.
>
> Others:
> - Add Xiao Ni as md/raid reviewer.
Two notes:
1) Why are you rebasing the tree right before sending it? There
should be zero need to do that, please don't.
2) Please switch to https://patch.msgid.link/ for you Link tags,
if they are just links to the patch submission. That makes it
clear this is the case, just the patch. You can use lore for
actual bug reports etc.
Pulled, but please change the above two things going forward.
--
Jens Axboe
^ permalink raw reply
* [GIT PULL] md-7.1-20260428
From: Yu Kuai @ 2026-04-28 14:33 UTC (permalink / raw)
To: Jens Axboe
Cc: linux-block, linux-raid, Song Liu, Li Nan, Xiao Ni,
Abd-Alrhman Masalkhi, Benjamin Marzinski, Junrui Luo, Keith Busch
Hi Jens,
Please consider pulling the following changes into your block-7.1
branch.
This pull request contains:
Bug Fixes:
- Fix a raid5 UAF on IO across the reshape position.
- Avoid failing RAID1/RAID10 devices for invalid IO errors.
- Fix RAID10 divide-by-zero when far_copies is zero.
- Restore bitmap grow through sysfs.
Cleanups:
- Use mddev_is_dm() instead of open-coding gendisk checks.
- Use ATTRIBUTE_GROUPS() for md default sysfs attributes.
- Replace open-coded wait loops with wait_event helpers.
Others:
- Add Xiao Ni as md/raid reviewer.
Thanks,
Kuai
---
The following changes since commit 0898a817621a2f0cddca8122d9b974003fe5036d:
cdrom, scsi: sr: propagate read-only status to block layer via set_disk_ro() (2026-04-27 15:52:51 -0600)
are available in the Git repository at:
https://git.kernel.org/pub/scm/linux/kernel/git/mdraid/linux.git tags/md-7.1-20260428
for you to fetch changes up to 3b2f70eab5a2cd15e27b1447e66e45302b28ff2c:
md: use ATTRIBUTE_GROUPS() for md default sysfs attributes (2026-04-28 20:44:38 +0800)
----------------------------------------------------------------
Abd-Alrhman Masalkhi (5):
md: replace wait loop with wait_event() in md_handle_request()
md: use mddev_lock_nointr() in mddev_suspend_and_lock_nointr()
md/raid1: replace wait loop with wait_event_idle() in raid1_write_request()
md: use mddev_is_dm() instead of open-coding gendisk checks
md: use ATTRIBUTE_GROUPS() for md default sysfs attributes
Benjamin Marzinski (1):
md/raid5: Fix UAF on IO across the reshape position
Junrui Luo (1):
md/raid10: fix divide-by-zero in setup_geo() with zero far_copies
Keith Busch (1):
md/raid1,raid10: don't fail devices for invalid IO errors
Xiao Ni (1):
MAINTAINERS: Add Xiao Ni as md/raid reviewer
Yu Kuai (3):
md: factor bitmap creation away from sysfs handling
md/md-bitmap: split bitmap sysfs groups
md/md-bitmap: add a none backend for bitmap grow
MAINTAINERS | 1 +
drivers/md/md-bitmap.c | 131 ++++++++++++++++++++++++++++++----
drivers/md/md-bitmap.h | 2 +-
drivers/md/md-llbitmap.c | 7 +-
drivers/md/md.c | 182 ++++++++++++++++++++++++++---------------------
drivers/md/md.h | 6 +-
drivers/md/raid1-10.c | 7 +-
drivers/md/raid1.c | 15 ++--
drivers/md/raid10.c | 2 +
drivers/md/raid5.c | 7 +-
10 files changed, 251 insertions(+), 109 deletions(-)
^ permalink raw reply
* [PATCH v2] md: skip redundant raid_disks update when value is unchanged
From: Abd-Alrhman Masalkhi @ 2026-04-28 13:05 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, Abd-Alrhman Masalkhi
Calling update_raid_disks() with the same value as the current one
can trigger unnecessary work. For example, RAID1 will reallocate
resources such as the mempool for r1bio.
Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
---
drivers/md/md.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index ac71640ff3a8..21b8ad17685f 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -4409,9 +4409,10 @@ raid_disks_store(struct mddev *mddev, const char *buf, size_t len)
err = mddev_suspend_and_lock(mddev);
if (err)
return err;
- if (mddev->pers)
- err = update_raid_disks(mddev, n);
- else if (mddev->reshape_position != MaxSector) {
+ if (mddev->pers) {
+ if (n != mddev->raid_disks)
+ err = update_raid_disks(mddev, n);
+ } else if (mddev->reshape_position != MaxSector) {
struct md_rdev *rdev;
int olddisks = mddev->raid_disks - mddev->delta_disks;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH] md/raid1: fix len reuse across rdevs in choose_first_rdev()
From: Abd-Alrhman Masalkhi @ 2026-04-28 11:53 UTC (permalink / raw)
To: Yu Kuai, song, paul.e.luse, xni, yukuai; +Cc: linux-raid, linux-kernel
In-Reply-To: <5c71cb6b-d860-4bcb-a900-a27544be7a17@fnnas.com>
Hi Kaui,
On Tue, Apr 28, 2026 at 16:23 +0800, Yu Kuai wrote:
> Hi,
>
> 在 2026/4/26 17:35, Abd-Alrhman Masalkhi 写道:
>> choose_first_rdev() initializes the variable len before iterating over
>> all rdevs, but passes it by reference to raid1_check_read_range(), which
>> it might update *len and return 0 depending on the layout of the bad
>> block region. As a result, 'len' can be modified during the first
>> iteration and reused for subsequent rdevs, causing later devices to be
>> evaluated with an incorrect length value.
>>
>> Fixes: 31a73331752d3 ("md/raid1: factor out read_first_rdev() from read_balance()")
>> Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
>> ---
>> drivers/md/raid1.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
>> index b549be9174bb..5f5dbf79c903 100644
>> --- a/drivers/md/raid1.c
>> +++ b/drivers/md/raid1.c
>> @@ -591,12 +591,12 @@ static int choose_first_rdev(struct r1conf *conf, struct r1bio *r1_bio,
>> int *max_sectors)
>> {
>> sector_t this_sector = r1_bio->sector;
>> - int len = r1_bio->sectors;
>> int disk;
>>
>> for (disk = 0 ; disk < conf->raid_disks * 2 ; disk++) {
>> struct md_rdev *rdev;
>> int read_len;
>> + int len = r1_bio->sectors;
>>
>> if (r1_bio->bios[disk] == IO_BLOCKED)
>> continue;
>
> This patch is wrong, choose_first_rdev() is used when raid1_should_read_first() is true,
> meaning the read overlaps an unsynced/resyncing area. Reset len can cause the problem that
> reading the same area can return different data.
>
Thank you for the detailed explanation. After carefully re-reading the
code and your feedback, I understand why the patch is wrong.
> --
> Thansk,
> Kuai
--
Best Regards,
Abd-Alrhman
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox