* Re: [QUESTION] Debugging some file data corruption
From: Kenta Akagi @ 2026-02-11 14:07 UTC (permalink / raw)
To: Calvin Owens
Cc: quwenruo.btrfs, linux-block, linux-raid, linux-btrfs,
linux-crypto, k
In-Reply-To: <aWU5VnDW8cHnnauK@mozart.vkv.me>
On 2026/01/13 3:11, Calvin Owens wrote:
> On Wednesday 11/12 at 07:32 +1030, Qu Wenruo wrote:
>> 在 2025/11/12 03:31, Calvin Owens 写道:
>>> Hello all,
>>>
>>> I'm looking for help debugging some corruption I recently encountered.
>>> It happened on 6.17.0, and I'm trying to reproduce it on 6.18-rc. This
>>> is not really actionable yet, I'm just looking for advice.
>>>
>>> After copying about 10TB of data to a btrfs+luks+mdraid1 across two 18TB
>>> drives,
>>
>> With LUKS in the middle, it makes any corruption pattern very human
>> unreadable.
>>
>> I guess it's not really feasible to try to reproduce the problem again since
>> it has 10TiB data involved?
>>
>> But if you can spend a lot of time waiting for data copy, mind to try
>> the following combination(s)?
>>
>> - btrfs on mdraid1
>> - btrfs RAID1 on raw two HDDs
>
> I re-ran the copies several times and never reproduced it. But I finally
> hit it again after I gave up, while making a backup on 6.18.0 with
> btrfs-raid1+luks:
>
> Opening filesystem to check...
> Checking filesystem on /dev/mapper/sdc_crypt
> UUID: f8223856-32cc-4dcf-8cee-9312e032c005
> [1/8] checking log skipped (none written)
> [1/7] checking root items (0:00:59 elapsed, 4875792 items checked)
> [2/7] checking extents (0:28:03 elapsed, 4583919 items checked)
> [3/7] checking free space tree (0:01:01 elapsed, 8253 items checked)
> [4/7] checking fs roots (0:20:30 elapsed, 10978 items checked)
> mirror 2 bytenr 870744010752 csum 0xdb1b27f0ca1a0139f7c65a0c0698a9a3f9e6ca6d624da7f70eecb3fc0f14ffc7 expected csum 0x2bce1cca32d98c3f83087f09980770a101b0560b1ddde7919fbbcd58a75f7d6b
> mirror 1 bytenr 2004063948800 csum 0xe3f0a16cc8f03705a89f81178d4617c2847d660b7171abe29b65b5b394a9aace expected csum 0xc85b7f37fb620e1a68754692fd7ca43846ca316de6485fc8a4b447bfeab78d78
> mirror 2 bytenr 3575828525056 csum 0xb9d9ee193d29b59b2015efed6151029c340a051c0338ec7ebca200363d304be8 expected csum 0xd645b7e5add1aa540a3440b78b7d31daa9545c925d32d2650d6bc61b7fdf4813
> mirror 1 bytenr 3714124914688 csum 0xcb2ff575e84a8e965b94bc8faf9e76d8f645742ee9cd503609efd78ac22623e4 expected csum 0x966b1d021450ffb6c47759161533e185f06a14a50c30ff881097a43b7ad6d6cc
> mirror 2 bytenr 4211891310592 csum 0xd1c11dabfa4bf3acea463479ab444bbc4c66dc9ba3257f09f4e1815bb46afac2 expected csum 0x17fff4d14269c69d84d267466c577ced3787fd9a9a445e36642067c47f129601
> mirror 2 bytenr 4328552914944 csum 0x02f75c04f1d921ce34f5b6b9bf40c3b0056971fc89989dad227fc45723938472 expected csum 0xdd6416d001ac47f16e68a24d1438244152355a0774142d4885e5a031c6938d93
> mirror 2 bytenr 4681011163136 csum 0x44c0b9d90fb258659e7377e93a96039afcadb501559a0cd831bf8c36f8fa1b2b expected csum 0x36c59223538807fc604537be5d686900031866626f3a1dc788755e92a74869cb
> mirror 1 bytenr 4808263344128 csum 0xfd6278ce98b1f15c8aefea981e5ba7a521fa1a08d0f642185abf72e215288618 expected csum 0x1108b8b604c5b21f7d7d80d32a1fd9c0c0e753cad8fb97967dfa3525105bf808
> mirror 1 bytenr 4993017057280 csum 0x033440e421102ec0c7b3057eae89dd80f300aecba70d3f1fcf5fe81c2cd6faba expected csum 0xb0e94e343b7291df9aae42a079bd0bba307a1c2ab81315361a49b0d8b6d53f49
> mirror 2 bytenr 5037246173184 csum 0x00b807ff8d0a31a79bb947e774c077916b0bd162dbf24fe43e4fca179e364214 expected csum 0x984635996e4c3fed6c701519e9f654b1b0adb06f3921522f6b687bbccd730271
> mirror 1 bytenr 5316786614272 csum 0x2805b36b130667ffaf187f1cc6bdab0802e5eb26332f3bae572202c9c34585dd expected csum 0xd7a2bab5bfddacddb610c6044504474c88962ed22d837a881faba8e4e60bee40
> mirror 2 bytenr 7293991006208 csum 0x68f917b93233bb6c7e49775c0c0deed66c47fe0027f3d4287a3b2c736fb25a1b expected csum 0x3662cf0b4a35cd0a0b71a475f35a92a6fefdcf21b7ee59a97b261bb6fbda1c8a
> [5/7] checking csums against data (33:30:05 elapsed, 6082759 items checked)
> ERROR: errors found in csum tree
> [6/7] checking root refs (0:00:00 elapsed, 3 items checked)
> [8/8] checking quota groups skipped (not enabled on this FS)
> found 8848080683008 bytes used, error(s) found
> total csum bytes: 68538889856
> total tree bytes: 75102781440
> total fs tree bytes: 180338688
> total extent tree bytes: 340852736
> btree space waste bytes: 5344101189
> file data blocks allocated: 8776199127040
> referenced 8772977901568
>
> The corruptions looked similar to the first time, couldn't get any new
> clues out of them. Unfortunately it was on LUKS again because I'd given
> up on reproducing this, I'll try without LUKS going forward.
>
> I realized the common factor betwen the original repro and this one was
> that I was additionally running an sftp copy of the same files over the
> network while the files were being copied between the two local volumes.
>
> mkfs.btrfs -m raid1 -d raid1 --csum blake2 /dev/sda /dev/sdb
> mount /dev/sda -o compress=zstd:1 /mnt
> rsync -Pav /data/ /mnt
>
> ...and then, concurrently from another machine:
>
> sftp -ar nas:/data .
>
> Can anybody else reproduce this corruption with that combo?
>
> Otherwise, I'll keep working on narrowing this down: the tests take ages
> to run but require very little actual human time from me, so I'm happy
> to keep trying. Any other suggestions are welcome!
Hi Calvin,
How about replacing one of your hard drives with a product from a completely
different manufacturer for isolate the issue?
I've seen this type of problem occur twice due to hardware,
and neither of them were using btrfs, md or luks.
The first case was about 12 years ago. I had a RAID-Z2 (RAID6) configured
with ZFS on Linux. There was a problem only with the HDDs connected to the
Marvell 88SE9128, and the problem was resolved when I changed to a different
SATA controller.
My memory is a bit hazy, but I believe ZFS detected a checksum inconsistency
during scrubbing only on the disk connected with the Marvell.
- However, since you say your USB enclosure has been in use for a long time,
it seems the controller is not the issue.
The other case was relatively recent, and I can't go into details for some reasons,
but there was a problem with the disk's firmware which resulted in data corruption.
Thanks,
Akagi
>
> Thanks,
> Calvin
>
^ permalink raw reply
* [PATCH AUTOSEL 6.19-6.6] md-cluster: fix NULL pointer dereference in process_metadata_update
From: Sasha Levin @ 2026-02-11 12:30 UTC (permalink / raw)
To: patches, stable; +Cc: Jiasheng Jiang, Yu Kuai, Sasha Levin, song, linux-raid
In-Reply-To: <20260211123112.1330287-1-sashal@kernel.org>
From: Jiasheng Jiang <jiashengjiangcool@gmail.com>
[ Upstream commit f150e753cb8dd756085f46e86f2c35ce472e0a3c ]
The function process_metadata_update() blindly dereferences the 'thread'
pointer (acquired via rcu_dereference_protected) within the wait_event()
macro.
While the code comment states "daemon thread must exist", there is a valid
race condition window during the MD array startup sequence (md_run):
1. bitmap_load() is called, which invokes md_cluster_ops->join().
2. join() starts the "cluster_recv" thread (recv_daemon).
3. At this point, recv_daemon is active and processing messages.
4. However, mddev->thread (the main MD thread) is not initialized until
later in md_run().
If a METADATA_UPDATED message is received from a remote node during this
specific window, process_metadata_update() will be called while
mddev->thread is still NULL, leading to a kernel panic.
To fix this, we must validate the 'thread' pointer. If it is NULL, we
release the held lock (no_new_dev_lockres) and return early, safely
ignoring the update request as the array is not yet fully ready to
process it.
Link: https://lore.kernel.org/linux-raid/20260117145903.28921-1-jiashengjiangcool@gmail.com
Signed-off-by: Jiasheng Jiang <jiashengjiangcool@gmail.com>
Signed-off-by: Yu Kuai <yukuai@fnnas.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
Now I have a comprehensive understanding of the issue. Let me summarize
my analysis.
---
## Detailed Analysis
### 1. Commit Message Analysis
The commit fixes a **NULL pointer dereference** in
`process_metadata_update()` in `drivers/md/md-cluster.c`. The subject
explicitly says "fix NULL pointer dereference" -- a strong indicator for
stable.
### 2. Code Change Analysis
The vulnerable code is at line 552-556 (before the fix):
```552:556:drivers/md/md-cluster.c
/* daemaon thread must exist */
thread = rcu_dereference_protected(mddev->thread, true);
wait_event(thread->wqueue,
(got_lock = mddev_trylock(mddev)) ||
test_bit(MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD,
&cinfo->state));
```
The code obtains `mddev->thread` via `rcu_dereference_protected()` and
**immediately dereferences `thread->wqueue`** without any NULL check. If
`thread` is NULL, this is a guaranteed kernel panic.
**Critical comparison**: All other uses of `mddev->thread` in `md-
cluster.c` (lines 352, 468, 571, 726, 1079) go through
`md_wakeup_thread()`, which has a **built-in NULL check**:
```8520:8531:drivers/md/md.c
void __md_wakeup_thread(struct md_thread __rcu *thread)
{
struct md_thread *t;
t = rcu_dereference(thread);
if (t) {
pr_debug("md: waking up MD thread %s.\n", t->tsk->comm);
set_bit(THREAD_WAKEUP, &t->flags);
if (wq_has_sleeper(&t->wqueue))
wake_up(&t->wqueue);
}
}
```
So `process_metadata_update()` is the **only location** in the file that
directly dereferences `mddev->thread` without safety.
### 3. The Race Condition
The vulnerability was introduced in commit `0ba959774e939` ("md-cluster:
use sync way to handle METADATA_UPDATED msg", 2017, v4.12). The author
of that commit was aware of the `thread->wqueue` dependency -- they even
wrote a follow-up commit `48df498daf62e` ("md: move bitmap_destroy to
the beginning of __md_stop") that explicitly states:
> "process_metadata_update is depended on mddev->thread->wqueue"
> "clustered raid could possible hang if array received a
METADATA_UPDATED msg after array unregistered mddev->thread"
This follow-up only addressed the **shutdown ordering** (moving
`bitmap_destroy` before `mddev_detach`), but did NOT add a NULL safety
check for the startup/error paths.
The race window during startup:
- `md_run()` calls `pers->run()` which sets `mddev->thread`
- Then `md_bitmap_create()` -> `join()` creates recv_thread
- Then `bitmap_load()` -> `load_bitmaps()` enables message processing
While the normal ordering seems safe, there are scenarios involving:
- Error paths during bitmap creation where `mddev_detach()` is called
(NULLing `mddev->thread`) while the recv_thread may still have work
pending
- Edge cases in `dm-raid` which has a different bitmap_load timing
- Future code changes that could affect the ordering
### 4. The Fix
The fix adds a simple NULL check:
```diff
thread = rcu_dereference_protected(mddev->thread, true);
+ if (!thread) {
+ pr_warn("md-cluster: Received metadata update but MD
thread is not ready\n");
+ dlm_unlock_sync(cinfo->no_new_dev_lockres);
+ return;
+ }
```
The fix properly:
- Checks for NULL before dereferencing `thread->wqueue`
- Releases the DLM lock (`no_new_dev_lockres`) acquired earlier in the
function (avoids deadlock on early return)
- Logs a warning for debugging
- Returns early, safely skipping the update (the array isn't fully ready
anyway)
- Removes the incorrect "daemaon" typo comment
### 5. Scope and Risk Assessment
- **Lines changed**: +6/-1, single file
- **Risk**: Near zero. The check only triggers when `thread` is NULL
(abnormal case). Normal operation is completely unaffected.
- **Subsystem**: MD RAID (clustered), mature subsystem present since
v4.12
- **Could break something**: No. This is purely defensive -- adding a
safety check that only activates in the error scenario.
### 6. User Impact
- **Who is affected**: Users of clustered MD RAID (enterprise/SAN
environments)
- **Severity if triggered**: Kernel panic/oops (NULL pointer
dereference)
- **Affected stable trees**: All versions since v4.12 (5.4, 5.10, 5.15,
6.1, 6.6, 6.12, etc.)
### 7. Stable Criteria Checklist
- **Obviously correct and tested**: Yes, trivially correct NULL check
with proper cleanup
- **Fixes a real bug**: Yes, NULL pointer dereference leading to kernel
panic
- **Important issue**: Yes, kernel crash
- **Small and contained**: Yes, 6-line change in one function in one
file
- **No new features**: Correct
- **Clean backport**: The fix should apply cleanly to all stable trees
since the code hasn't materially changed since v4.12
**YES**
drivers/md/md-cluster.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c
index 11f1e91d387d8..896279988dfd5 100644
--- a/drivers/md/md-cluster.c
+++ b/drivers/md/md-cluster.c
@@ -549,8 +549,13 @@ static void process_metadata_update(struct mddev *mddev, struct cluster_msg *msg
dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR);
- /* daemaon thread must exist */
thread = rcu_dereference_protected(mddev->thread, true);
+ if (!thread) {
+ pr_warn("md-cluster: Received metadata update but MD thread is not ready\n");
+ dlm_unlock_sync(cinfo->no_new_dev_lockres);
+ return;
+ }
+
wait_event(thread->wqueue,
(got_lock = mddev_trylock(mddev)) ||
test_bit(MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD, &cinfo->state));
--
2.51.0
^ permalink raw reply related
* [PATCH AUTOSEL 6.19-6.18] md raid: fix hang when stopping arrays with metadata through dm-raid
From: Sasha Levin @ 2026-02-11 12:30 UTC (permalink / raw)
To: patches, stable; +Cc: Heinz Mauelshagen, Yu Kuai, Sasha Levin, song, linux-raid
In-Reply-To: <20260211123112.1330287-1-sashal@kernel.org>
From: Heinz Mauelshagen <heinzm@redhat.com>
[ Upstream commit cefcb9297fbdb6d94b61787b4f8d84f55b741470 ]
When using device-mapper's dm-raid target, stopping a RAID array can cause
the system to hang under specific conditions.
This occurs when:
- A dm-raid managed device tree is suspended from top to bottom
(the top-level RAID device is suspended first, followed by its
underlying metadata and data devices)
- The top-level RAID device is then removed
Removing the top-level device triggers a hang in the following sequence:
the dm-raid destructor calls md_stop(), which tries to flush the
write-intent bitmap by writing to the metadata sub-devices. However, these
devices are already suspended, making them unable to complete the write-intent
operations and causing an indefinite block.
Fix:
- Prevent bitmap flushing when md_stop() is called from dm-raid
destructor context
and avoid a quiescing/unquescing cycle which could also cause I/O
- Still allow write-intent bitmap flushing when called from dm-raid
suspend context
This ensures that RAID array teardown can complete successfully even when the
underlying devices are in a suspended state.
This second patch uses md_is_rdwr() to distinguish between suspend and
destructor paths as elaborated on above.
Link: https://lore.kernel.org/linux-raid/CAM23VxqYrwkhKEBeQrZeZwQudbiNey2_8B_SEOLqug=pXxaFrA@mail.gmail.com
Signed-off-by: Heinz Mauelshagen <heinzm@redhat.com>
Signed-off-by: Yu Kuai <yukuai@fnnas.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Complete Analysis
### 1. What the Bug Is
This commit fixes a **system hang** (indefinite block/deadlock) when
stopping dm-raid managed RAID arrays. The hang scenario is:
1. A dm-raid device tree is suspended top-to-bottom (top-level RAID
device first, then underlying metadata/data devices)
2. The top-level RAID device is removed (`raid_dtr` destructor)
3. `raid_dtr()` → `md_stop()` → `__md_stop_writes()` tries to:
- Quiesce the RAID personality (`pers->quiesce()`)
- Flush the write-intent bitmap to metadata devices
(`bitmap_ops->flush()`)
4. But the metadata devices are already suspended and **cannot complete
I/O**
5. The flush waits indefinitely → **system hang**
This is a real, user-reported bug (Link in commit message points to a
lore report).
### 2. The Fix
The fix adds a conditional guard around the quiesce and bitmap flush in
`__md_stop_writes()`:
```c
if (md_is_rdwr(mddev) || !mddev_is_dm(mddev)) {
// quiesce + bitmap flush
}
```
This condition skips the quiesce and bitmap flush **only** when:
- The device is a dm-raid device (`mddev_is_dm()` returns true), AND
- The device is NOT in read-write mode (`md_is_rdwr()` returns false)
The clever trick: `raid_postsuspend()` (suspend path) already calls
`md_stop_writes()` while the device is still `MD_RDWR`, so the bitmap
flush proceeds normally during suspend. Then it sets `rs->md.ro =
MD_RDONLY`. Later when `raid_dtr()` calls `md_stop()` →
`__md_stop_writes()`, the device is `MD_RDONLY`, so the condition is
false and the dangerous I/O is skipped.
For non-dm md arrays (`!mddev_is_dm()` is true), the condition is always
true and behavior is unchanged.
### 3. Code Change Scope
- **1 file changed**: `drivers/md/md.c`
- **8 insertions, 6 deletions** (net +2 lines)
- Only touches the `__md_stop_writes()` function
- Small and surgical
### 4. Critical Dependency Issue
The commit message explicitly says **"This second patch"**, indicating
it's part of a 2-patch series. The first patch is `55dcfdf8af9c3` ("dm
raid: use proper md_ro_state enumerators"), which:
- Added `rs->md.ro = MD_RDONLY;` to `raid_postsuspend()` in `dm-raid.c`
- Without this line, when `raid_dtr` runs, `mddev->ro` is still
`MD_RDWR` (from `raid_resume`), so `md_is_rdwr()` returns true, and
the quiesce/flush is NOT skipped → the hang still occurs!
**This means the fix (`cefcb9297fbdb`) CANNOT work without the
prerequisite (`55dcfdf8af9c3`).**
The prerequisite `55dcfdf8af9c3` was merged for v6.18. It is:
- Present in 6.18.y
- **NOT** present in 6.12.y, 6.6.y, 6.1.y, or 5.15.y
### 5. Additional Backport Complications
For older stable trees (6.12.y and earlier), the code context has
changed significantly:
- v6.12+: `bitmap_ops->flush()` (ops-based interface)
- v6.11 and earlier: `md_bitmap_flush()` (direct function call)
- The `md_bitmap_enabled()` guard was added between v6.12 and current
- The `serialize_policy` field changed to a flag bit
- `md_stop_writes()` in v6.6 includes `set_bit(MD_RECOVERY_FROZEN)` and
sync thread reaping, which was later moved to the callers
### 6. Is the Bug Present in Older Stable Trees?
**Yes**, the underlying bug (bitmap flush blocking on suspended metadata
devices) exists in all kernel versions with dm-raid. In v6.6/v6.1,
`__md_stop_writes()` also calls `md_bitmap_flush()` and
`pers->quiesce()` unconditionally, and the same hang can occur when
`raid_dtr` runs after `raid_postsuspend`.
However, to fix it in older trees, you would need BOTH:
1. The prerequisite that sets `ro = MD_RDONLY` in `raid_postsuspend`
(equivalent of `55dcfdf8af9c3`)
2. This fix that checks `md_is_rdwr()` in `__md_stop_writes` (this
commit)
And both would need adaptation to the different code context.
### 7. Risk Assessment
- **Severity of bug**: HIGH — system hang is a serious issue, especially
for enterprise users of dm-raid (LVM RAID, etc.)
- **Risk of regression**: LOW-MEDIUM — the fix only changes behavior for
dm-raid devices in the destructor path (when `!md_is_rdwr &&
mddev_is_dm`); all other paths are unchanged
- **Size**: Very small (8 insertions, 6 deletions)
- **Dependency complexity**: HIGH — requires prerequisite commit and
significant code context differences across versions
### 8. Verdict
This commit fixes a **real, user-reported system hang** in dm-raid
teardown, which is clearly important for stable. The fix itself is
small, surgical, and well-understood. However, it has a **hard
dependency** on `55dcfdf8af9c3` ("dm raid: use proper md_ro_state
enumerators") which adds the critical `rs->md.ro = MD_RDONLY` line in
`raid_postsuspend()`. Without that prerequisite, the `md_is_rdwr()`
check in this fix would never distinguish between suspend and destructor
paths, and the fix would be completely ineffective.
For 6.18.y, the prerequisite is present and this patch could apply
(possibly with minor context adjustments). For older LTS trees (6.12.y,
6.6.y, 6.1.y), both this commit and the prerequisite (with appropriate
context adaptations) would need to be backported together.
Given that:
1. It fixes a definite system hang (high severity)
2. It's small and well-contained
3. It has a clear dependency that must also be backported
4. dm-raid (LVM RAID) is widely used in enterprise environments
5. The author is from Red Hat (enterprise focus) and it was reported by
a real user
This is a **YES** for backporting, with the strong caveat that the
prerequisite commit `55dcfdf8af9c3` must be included in any backport.
**YES**
drivers/md/md.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 6d73f6e196a9f..ac71640ff3a81 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -6848,13 +6848,15 @@ static void __md_stop_writes(struct mddev *mddev)
{
timer_delete_sync(&mddev->safemode_timer);
- if (mddev->pers && mddev->pers->quiesce) {
- mddev->pers->quiesce(mddev, 1);
- mddev->pers->quiesce(mddev, 0);
- }
+ if (md_is_rdwr(mddev) || !mddev_is_dm(mddev)) {
+ if (mddev->pers && mddev->pers->quiesce) {
+ mddev->pers->quiesce(mddev, 1);
+ mddev->pers->quiesce(mddev, 0);
+ }
- if (md_bitmap_enabled(mddev, true))
- mddev->bitmap_ops->flush(mddev);
+ if (md_bitmap_enabled(mddev, true))
+ mddev->bitmap_ops->flush(mddev);
+ }
if (md_is_rdwr(mddev) &&
((!mddev->in_sync && !mddev_is_clustered(mddev)) ||
--
2.51.0
^ permalink raw reply related
* Re: [PATCH 2/2] md/raid1: serialize overlapped io for writemostly disk
From: Xiao Ni @ 2026-02-11 3:26 UTC (permalink / raw)
To: yukuai; +Cc: song, linux-raid, linan666
In-Reply-To: <a753611f-91ee-4cee-97c8-706154d1cade@fnnas.com>
On Wed, Feb 11, 2026 at 11:15 AM Yu Kuai <yukuai@fnnas.com> wrote:
>
> Hi,
>
> 在 2026/2/11 10:44, Xiao Ni 写道:
> > On Wed, Feb 11, 2026 at 10:32 AM Yu Kuai <yukuai@fnnas.com> wrote:
> >> Hi,
> >>
> >> 在 2026/2/6 13:38, Xiao Ni 写道:
> >>> In behind mode, overlap bios for writemostly device are queued. They
> >>> In behind mode, bios which overlap the bio from the interval tree
> >>> need to wait in waitqueue. Those bios will be handled once the in-tree
> >>> bio finishes. They are waken up and try to get the tree lock. The bio
> >>> which gets the lock will be handled. So the sequence can't be guaranteed.
> >>>
> >>> For example
> >>> bio1(100,200)
> >>> bio2(150,200)
> >>> bio3(150,300)
> >>> The write sequence of fast device is bio1,bio2,bio3. But the write
> >>> sequence of slow device is bio1,bio3,bio2. This causes data corruption.
> >>> Replace waitqueue with a fifo list to guarantee the write sequence.
> >> To be honest, I think this is fine with the respect user won't send overlap
> >> bios. In this case, bio1 is done in fast disk and pending in slow disk, then
> >> bio2 will stuck while issuing and waiting for bio1 to return from slow disk.
> >> So send bio3 in this case is not expected, and if you do you can't guarantee
> >> the complete order from fast disk as bio2, bio3 as well.
> > Hi Kuai
> >
> > In write behind mode, raid1 returns bio1 to the upper layer once the
> > write on the fast disk finishes. The upper layer (app/filesystem)
> > thinks that bio1 has finished, while the write of bio1 to the slow
> > disk is still in progress. So bio2 will not be stuck while issuing, am
> > I right? If so, bio2 can be submitted to raid1 once the write of bio1
> > to the fast disk finishes. And bio3 can be submitted to raid1 once the
> > write of bio2 to fast disk finishes.
>
> I just take a look at raid1 code, turns out raid1_write_request() just allocate
> bio and issue it directly in each rdev iteration, I misunderstood.
>
> This solution looks fine to me, however, I'll suggest to keep the wait_queue and
> use prepare_to_wait_exclusive() to guarantee the fifo order.
Thanks for the suggestion. I'll use prepare_to_wait_exclusive and send v2.
Best Regards
Xiao
>
> >
> > Best Regards
> > Xiao
> >>> Signed-off-by: Xiao Ni <xni@redhat.com>
> >>> ---
> >>> drivers/md/md.c | 1 -
> >>> drivers/md/md.h | 4 +++-
> >>> drivers/md/raid1.c | 39 +++++++++++++++++++++++++++++----------
> >>> 3 files changed, 32 insertions(+), 12 deletions(-)
> >>>
> >>> diff --git a/drivers/md/md.c b/drivers/md/md.c
> >>> index 59cd303548de..ab91d17c2d68 100644
> >>> --- a/drivers/md/md.c
> >>> +++ b/drivers/md/md.c
> >>> @@ -188,7 +188,6 @@ static int rdev_init_serial(struct md_rdev *rdev)
> >>>
> >>> spin_lock_init(&serial_tmp->serial_lock);
> >>> serial_tmp->serial_rb = RB_ROOT_CACHED;
> >>> - init_waitqueue_head(&serial_tmp->serial_io_wait);
> >>> }
> >>>
> >>> rdev->serial = serial;
> >>> diff --git a/drivers/md/md.h b/drivers/md/md.h
> >>> index ac84289664cd..64ffbb2efb87 100644
> >>> --- a/drivers/md/md.h
> >>> +++ b/drivers/md/md.h
> >>> @@ -126,7 +126,6 @@ enum sync_action {
> >>> struct serial_in_rdev {
> >>> struct rb_root_cached serial_rb;
> >>> spinlock_t serial_lock;
> >>> - wait_queue_head_t serial_io_wait;
> >>> };
> >>>
> >>> /*
> >>> @@ -382,6 +381,9 @@ struct serial_info {
> >>> sector_t start; /* start sector of rb node */
> >>> sector_t last; /* end sector of rb node */
> >>> sector_t _subtree_last; /* highest sector in subtree of rb node */
> >>> + struct list_head list_node;
> >>> + struct list_head waiters;
> >>> + struct completion ready;
> >>> };
> >>>
> >>> /*
> >>> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> >>> index a41b1ec3d695..38c73538d038 100644
> >>> --- a/drivers/md/raid1.c
> >>> +++ b/drivers/md/raid1.c
> >>> @@ -57,19 +57,25 @@ INTERVAL_TREE_DEFINE(struct serial_info, node, sector_t, _subtree_last,
> >>> START, LAST, static inline, raid1_rb);
> >>>
> >>> static int check_and_add_serial(struct md_rdev *rdev, struct r1bio *r1_bio,
> >>> - struct serial_info *si, int idx)
> >>> + struct serial_info *si)
> >>> {
> >>> unsigned long flags;
> >>> int ret = 0;
> >>> sector_t lo = r1_bio->sector;
> >>> sector_t hi = lo + r1_bio->sectors - 1;
> >>> + int idx = sector_to_idx(r1_bio->sector);
> >>> struct serial_in_rdev *serial = &rdev->serial[idx];
> >>> + struct serial_info *head_si;
> >>>
> >>> spin_lock_irqsave(&serial->serial_lock, flags);
> >>> /* collision happened */
> >>> - if (raid1_rb_iter_first(&serial->serial_rb, lo, hi))
> >>> + head_si = raid1_rb_iter_first(&serial->serial_rb, lo, hi);
> >>> + if (head_si && head_si != si) {
> >>> + si->start = lo;
> >>> + si->last = hi;
> >>> + list_add_tail(&si->list_node, &head_si->waiters);
> >>> ret = -EBUSY;
> >>> - else {
> >>> + } else if (!head_si) {
> >>> si->start = lo;
> >>> si->last = hi;
> >>> raid1_rb_insert(si, &serial->serial_rb);
> >>> @@ -83,19 +89,23 @@ static void wait_for_serialization(struct md_rdev *rdev, struct r1bio *r1_bio)
> >>> {
> >>> struct mddev *mddev = rdev->mddev;
> >>> struct serial_info *si;
> >>> - int idx = sector_to_idx(r1_bio->sector);
> >>> - struct serial_in_rdev *serial = &rdev->serial[idx];
> >>>
> >>> if (WARN_ON(!mddev->serial_info_pool))
> >>> return;
> >>> si = mempool_alloc(mddev->serial_info_pool, GFP_NOIO);
> >>> - wait_event(serial->serial_io_wait,
> >>> - check_and_add_serial(rdev, r1_bio, si, idx) == 0);
> >>> + INIT_LIST_HEAD(&si->waiters);
> >>> + INIT_LIST_HEAD(&si->list_node);
> >>> + init_completion(&si->ready);
> >>> + while (check_and_add_serial(rdev, r1_bio, si)) {
> >>> + wait_for_completion(&si->ready);
> >>> + reinit_completion(&si->ready);
> >>> + }
> >>> }
> >>>
> >>> static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi)
> >>> {
> >>> struct serial_info *si;
> >>> + struct serial_info *first_si;
> >>> unsigned long flags;
> >>> int found = 0;
> >>> struct mddev *mddev = rdev->mddev;
> >>> @@ -106,16 +116,25 @@ static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi)
> >>> for (si = raid1_rb_iter_first(&serial->serial_rb, lo, hi);
> >>> si; si = raid1_rb_iter_next(si, lo, hi)) {
> >>> if (si->start == lo && si->last == hi) {
> >>> - raid1_rb_remove(si, &serial->serial_rb);
> >>> - mempool_free(si, mddev->serial_info_pool);
> >>> found = 1;
> >>> break;
> >>> }
> >>> }
> >>> if (!found)
> >>> WARN(1, "The write IO is not recorded for serialization\n");
> >>> + else {
> >>> + raid1_rb_remove(si, &serial->serial_rb);
> >>> + if (!list_empty(&si->waiters)) {
> >>> + first_si = list_first_entry(&si->waiters,
> >>> + struct serial_info, list_node);
> >>> + list_del_init(&first_si->list_node);
> >>> + list_splice_init(&si->waiters, &first_si->waiters);
> >>> + raid1_rb_insert(first_si, &serial->serial_rb);
> >>> + complete(&first_si->ready);
> >>> + }
> >>> + mempool_free(si, mddev->serial_info_pool);
> >>> + }
> >>> spin_unlock_irqrestore(&serial->serial_lock, flags);
> >>> - wake_up(&serial->serial_io_wait);
> >>> }
> >>>
> >>> /*
> >> --
> >> Thansk,
> >> Kuai
> >>
> >
> --
> Thansk,
> Kuai
>
^ permalink raw reply
* Re: [PATCH 2/2] md/raid1: serialize overlapped io for writemostly disk
From: Yu Kuai @ 2026-02-11 3:15 UTC (permalink / raw)
To: Xiao Ni; +Cc: song, linux-raid, linan666, yukuai
In-Reply-To: <CALTww29NpmNbEb79KbVCX-rAF4o39rEd3-P1TjiDTc1OWpQiAw@mail.gmail.com>
Hi,
在 2026/2/11 10:44, Xiao Ni 写道:
> On Wed, Feb 11, 2026 at 10:32 AM Yu Kuai <yukuai@fnnas.com> wrote:
>> Hi,
>>
>> 在 2026/2/6 13:38, Xiao Ni 写道:
>>> In behind mode, overlap bios for writemostly device are queued. They
>>> In behind mode, bios which overlap the bio from the interval tree
>>> need to wait in waitqueue. Those bios will be handled once the in-tree
>>> bio finishes. They are waken up and try to get the tree lock. The bio
>>> which gets the lock will be handled. So the sequence can't be guaranteed.
>>>
>>> For example
>>> bio1(100,200)
>>> bio2(150,200)
>>> bio3(150,300)
>>> The write sequence of fast device is bio1,bio2,bio3. But the write
>>> sequence of slow device is bio1,bio3,bio2. This causes data corruption.
>>> Replace waitqueue with a fifo list to guarantee the write sequence.
>> To be honest, I think this is fine with the respect user won't send overlap
>> bios. In this case, bio1 is done in fast disk and pending in slow disk, then
>> bio2 will stuck while issuing and waiting for bio1 to return from slow disk.
>> So send bio3 in this case is not expected, and if you do you can't guarantee
>> the complete order from fast disk as bio2, bio3 as well.
> Hi Kuai
>
> In write behind mode, raid1 returns bio1 to the upper layer once the
> write on the fast disk finishes. The upper layer (app/filesystem)
> thinks that bio1 has finished, while the write of bio1 to the slow
> disk is still in progress. So bio2 will not be stuck while issuing, am
> I right? If so, bio2 can be submitted to raid1 once the write of bio1
> to the fast disk finishes. And bio3 can be submitted to raid1 once the
> write of bio2 to fast disk finishes.
I just take a look at raid1 code, turns out raid1_write_request() just allocate
bio and issue it directly in each rdev iteration, I misunderstood.
This solution looks fine to me, however, I'll suggest to keep the wait_queue and
use prepare_to_wait_exclusive() to guarantee the fifo order.
>
> Best Regards
> Xiao
>>> Signed-off-by: Xiao Ni <xni@redhat.com>
>>> ---
>>> drivers/md/md.c | 1 -
>>> drivers/md/md.h | 4 +++-
>>> drivers/md/raid1.c | 39 +++++++++++++++++++++++++++++----------
>>> 3 files changed, 32 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/drivers/md/md.c b/drivers/md/md.c
>>> index 59cd303548de..ab91d17c2d68 100644
>>> --- a/drivers/md/md.c
>>> +++ b/drivers/md/md.c
>>> @@ -188,7 +188,6 @@ static int rdev_init_serial(struct md_rdev *rdev)
>>>
>>> spin_lock_init(&serial_tmp->serial_lock);
>>> serial_tmp->serial_rb = RB_ROOT_CACHED;
>>> - init_waitqueue_head(&serial_tmp->serial_io_wait);
>>> }
>>>
>>> rdev->serial = serial;
>>> diff --git a/drivers/md/md.h b/drivers/md/md.h
>>> index ac84289664cd..64ffbb2efb87 100644
>>> --- a/drivers/md/md.h
>>> +++ b/drivers/md/md.h
>>> @@ -126,7 +126,6 @@ enum sync_action {
>>> struct serial_in_rdev {
>>> struct rb_root_cached serial_rb;
>>> spinlock_t serial_lock;
>>> - wait_queue_head_t serial_io_wait;
>>> };
>>>
>>> /*
>>> @@ -382,6 +381,9 @@ struct serial_info {
>>> sector_t start; /* start sector of rb node */
>>> sector_t last; /* end sector of rb node */
>>> sector_t _subtree_last; /* highest sector in subtree of rb node */
>>> + struct list_head list_node;
>>> + struct list_head waiters;
>>> + struct completion ready;
>>> };
>>>
>>> /*
>>> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
>>> index a41b1ec3d695..38c73538d038 100644
>>> --- a/drivers/md/raid1.c
>>> +++ b/drivers/md/raid1.c
>>> @@ -57,19 +57,25 @@ INTERVAL_TREE_DEFINE(struct serial_info, node, sector_t, _subtree_last,
>>> START, LAST, static inline, raid1_rb);
>>>
>>> static int check_and_add_serial(struct md_rdev *rdev, struct r1bio *r1_bio,
>>> - struct serial_info *si, int idx)
>>> + struct serial_info *si)
>>> {
>>> unsigned long flags;
>>> int ret = 0;
>>> sector_t lo = r1_bio->sector;
>>> sector_t hi = lo + r1_bio->sectors - 1;
>>> + int idx = sector_to_idx(r1_bio->sector);
>>> struct serial_in_rdev *serial = &rdev->serial[idx];
>>> + struct serial_info *head_si;
>>>
>>> spin_lock_irqsave(&serial->serial_lock, flags);
>>> /* collision happened */
>>> - if (raid1_rb_iter_first(&serial->serial_rb, lo, hi))
>>> + head_si = raid1_rb_iter_first(&serial->serial_rb, lo, hi);
>>> + if (head_si && head_si != si) {
>>> + si->start = lo;
>>> + si->last = hi;
>>> + list_add_tail(&si->list_node, &head_si->waiters);
>>> ret = -EBUSY;
>>> - else {
>>> + } else if (!head_si) {
>>> si->start = lo;
>>> si->last = hi;
>>> raid1_rb_insert(si, &serial->serial_rb);
>>> @@ -83,19 +89,23 @@ static void wait_for_serialization(struct md_rdev *rdev, struct r1bio *r1_bio)
>>> {
>>> struct mddev *mddev = rdev->mddev;
>>> struct serial_info *si;
>>> - int idx = sector_to_idx(r1_bio->sector);
>>> - struct serial_in_rdev *serial = &rdev->serial[idx];
>>>
>>> if (WARN_ON(!mddev->serial_info_pool))
>>> return;
>>> si = mempool_alloc(mddev->serial_info_pool, GFP_NOIO);
>>> - wait_event(serial->serial_io_wait,
>>> - check_and_add_serial(rdev, r1_bio, si, idx) == 0);
>>> + INIT_LIST_HEAD(&si->waiters);
>>> + INIT_LIST_HEAD(&si->list_node);
>>> + init_completion(&si->ready);
>>> + while (check_and_add_serial(rdev, r1_bio, si)) {
>>> + wait_for_completion(&si->ready);
>>> + reinit_completion(&si->ready);
>>> + }
>>> }
>>>
>>> static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi)
>>> {
>>> struct serial_info *si;
>>> + struct serial_info *first_si;
>>> unsigned long flags;
>>> int found = 0;
>>> struct mddev *mddev = rdev->mddev;
>>> @@ -106,16 +116,25 @@ static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi)
>>> for (si = raid1_rb_iter_first(&serial->serial_rb, lo, hi);
>>> si; si = raid1_rb_iter_next(si, lo, hi)) {
>>> if (si->start == lo && si->last == hi) {
>>> - raid1_rb_remove(si, &serial->serial_rb);
>>> - mempool_free(si, mddev->serial_info_pool);
>>> found = 1;
>>> break;
>>> }
>>> }
>>> if (!found)
>>> WARN(1, "The write IO is not recorded for serialization\n");
>>> + else {
>>> + raid1_rb_remove(si, &serial->serial_rb);
>>> + if (!list_empty(&si->waiters)) {
>>> + first_si = list_first_entry(&si->waiters,
>>> + struct serial_info, list_node);
>>> + list_del_init(&first_si->list_node);
>>> + list_splice_init(&si->waiters, &first_si->waiters);
>>> + raid1_rb_insert(first_si, &serial->serial_rb);
>>> + complete(&first_si->ready);
>>> + }
>>> + mempool_free(si, mddev->serial_info_pool);
>>> + }
>>> spin_unlock_irqrestore(&serial->serial_lock, flags);
>>> - wake_up(&serial->serial_io_wait);
>>> }
>>>
>>> /*
>> --
>> Thansk,
>> Kuai
>>
>
--
Thansk,
Kuai
^ permalink raw reply
* Re: [PATCH 2/2] md/raid1: serialize overlapped io for writemostly disk
From: Xiao Ni @ 2026-02-11 2:50 UTC (permalink / raw)
To: yukuai; +Cc: song, linux-raid, linan666
In-Reply-To: <CALTww29NpmNbEb79KbVCX-rAF4o39rEd3-P1TjiDTc1OWpQiAw@mail.gmail.com>
On Wed, Feb 11, 2026 at 10:44 AM Xiao Ni <xni@redhat.com> wrote:
>
> On Wed, Feb 11, 2026 at 10:32 AM Yu Kuai <yukuai@fnnas.com> wrote:
> >
> > Hi,
> >
> > 在 2026/2/6 13:38, Xiao Ni 写道:
> > > In behind mode, overlap bios for writemostly device are queued. They
> > > In behind mode, bios which overlap the bio from the interval tree
> > > need to wait in waitqueue. Those bios will be handled once the in-tree
> > > bio finishes. They are waken up and try to get the tree lock. The bio
> > > which gets the lock will be handled. So the sequence can't be guaranteed.
> > >
> > > For example
> > > bio1(100,200)
> > > bio2(150,200)
> > > bio3(150,300)
> > > The write sequence of fast device is bio1,bio2,bio3. But the write
> > > sequence of slow device is bio1,bio3,bio2. This causes data corruption.
> > > Replace waitqueue with a fifo list to guarantee the write sequence.
> >
> > To be honest, I think this is fine with the respect user won't send overlap
> > bios. In this case, bio1 is done in fast disk and pending in slow disk, then
> > bio2 will stuck while issuing and waiting for bio1 to return from slow disk.
> > So send bio3 in this case is not expected, and if you do you can't guarantee
> > the complete order from fast disk as bio2, bio3 as well.
>
> Hi Kuai
>
> In write behind mode, raid1 returns bio1 to the upper layer once the
> write on the fast disk finishes. The upper layer (app/filesystem)
> thinks that bio1 has finished, while the write of bio1 to the slow
> disk is still in progress. So bio2 will not be stuck while issuing, am
> I right? If so, bio2 can be submitted to raid1 once the write of bio1
> to the fast disk finishes. And bio3 can be submitted to raid1 once the
> write of bio2 to fast disk finishes.
By the way, it's reported by our customer, there is a data corruption
by the following test script:
#!/bin/sh
disk1=/dev/loop0
disk2=/dev/loop1
mddev=/dev/md0
mount_md=/data-md
mount_disk1=/data-1
mount_disk2=/data-2
bitmap=/root/bitmap
test_prg=/root/test-serializewrite
test_num=1000
test_str=abcdefghijklmnopqrstuvwxyz
loop=0
touch MD-TEST
while [ -f MD-TEST ]; do
set -x
loop=$((loop + 1))
echo "START LOOP=$loop at $(date)"
echo "# lsblk"
lsblk
echo "# dmsetup"
dmsetup create disk-500ms --table "0 $(blockdev --getsz $disk2)
delay $disk2 0 500"
sleep 2
echo "# mdadm"
#mdadm --create $mddev --run --assume-clean --force --level=1
--write-behind=1024 --bitmap=$bitmap --raid-devices=2 $disk1
--write-mostly /dev/mapper/disk-500ms
mdadm --create $mddev --run --assume-clean --force --level=1
--write-behind=1024 --bitmap=internal --raid-devices=2 $disk1
--write-mostly /dev/mapper/disk-500ms
echo "# cat /proc/mdstat"
cat /proc/mdstat
#echo "# mdadm -X $bitmap"
#mdadm -X $bitmap
echo "# mkfs.xfs -f $mddev"
mkfs.xfs -f $mddev
echo "# mount $mddev $mount_md"
mount $mddev $mount_md
set +x
echo "# $test_prg"
for n in $(seq 1 $test_num); do
$test_prg $mount_md/test.$n $test_str &
done
while true; do
sleep 2
pgrep -f $(basename $test_prg) > /dev/null
if [ $? -ne 0 ]; then
break
fi
done
set -x
echo "# cat /proc/mdstat"
cat /proc/mdstat
#echo "# mdadm -X $bitmap"
#mdadm -X $bitmap
echo "# umount $mount_md"
sleep 10
while true; do
sleep 2
umount $mount_md
if [ $? -eq 0 ]; then
break
fi
done
echo "# mdadm --stop $mddev"
mdadm --stop $mddev
echo "# dmsetup remove disk-500ms"
while true; do
dmsetup remove disk-500ms
if [ $? -ne 0 ]; then
sleep 5
else
break
fi
done
offset=$(mdadm --examine $disk1 | awk -F': ' '/Data Offset/ {print
$2}' | awk '{print $1}')
offset=$((offset * 512))
echo "# mount -o ro,offset=$offset,nouuid $disk1 $mount_disk1"
mount -o ro,offset=$offset,nouuid $disk1 $mount_disk1
offset=$(mdadm --examine $disk2 | awk -F': ' '/Data Offset/ {print
$2}' | awk '{print $1}')
#offset=$(mdadm --examine /dev/mapper/disk-500ms | awk -F': '
'/Data Offset/ {print $2}' | awk '{print $1}')
offset=$((offset * 512))
echo "# mount -o ro,offset=$offset,nouuid $disk2 $mount_disk2"
#echo "# mount -o ro,offset=$offset,nouuid /dev/mapper/disk-500ms
$mount_disk2"
mount -o ro,offset=$offset,nouuid $disk2 $mount_disk2
#mount -o ro,offset=$offset,nouuid /dev/mapper/disk-500ms $mount_disk2
echo "# diff -rq $mount_disk1 $mount_disk2"
diff -rq $mount_disk1 $mount_disk2
if [ $? -eq 0 ]; then
echo "@@@ PASS (loop=$loop)"
else
echo "@@@ FAIL (loop=$loop)"
fi
umount $mount_disk1
umount $mount_disk2
mdadm --zero-superblock $disk1
mdadm --zero-superblock $disk2
sleep 10
set +x
done
>
> Best Regards
> Xiao
> >
> > >
> > > Signed-off-by: Xiao Ni <xni@redhat.com>
> > > ---
> > > drivers/md/md.c | 1 -
> > > drivers/md/md.h | 4 +++-
> > > drivers/md/raid1.c | 39 +++++++++++++++++++++++++++++----------
> > > 3 files changed, 32 insertions(+), 12 deletions(-)
> > >
> > > diff --git a/drivers/md/md.c b/drivers/md/md.c
> > > index 59cd303548de..ab91d17c2d68 100644
> > > --- a/drivers/md/md.c
> > > +++ b/drivers/md/md.c
> > > @@ -188,7 +188,6 @@ static int rdev_init_serial(struct md_rdev *rdev)
> > >
> > > spin_lock_init(&serial_tmp->serial_lock);
> > > serial_tmp->serial_rb = RB_ROOT_CACHED;
> > > - init_waitqueue_head(&serial_tmp->serial_io_wait);
> > > }
> > >
> > > rdev->serial = serial;
> > > diff --git a/drivers/md/md.h b/drivers/md/md.h
> > > index ac84289664cd..64ffbb2efb87 100644
> > > --- a/drivers/md/md.h
> > > +++ b/drivers/md/md.h
> > > @@ -126,7 +126,6 @@ enum sync_action {
> > > struct serial_in_rdev {
> > > struct rb_root_cached serial_rb;
> > > spinlock_t serial_lock;
> > > - wait_queue_head_t serial_io_wait;
> > > };
> > >
> > > /*
> > > @@ -382,6 +381,9 @@ struct serial_info {
> > > sector_t start; /* start sector of rb node */
> > > sector_t last; /* end sector of rb node */
> > > sector_t _subtree_last; /* highest sector in subtree of rb node */
> > > + struct list_head list_node;
> > > + struct list_head waiters;
> > > + struct completion ready;
> > > };
> > >
> > > /*
> > > diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> > > index a41b1ec3d695..38c73538d038 100644
> > > --- a/drivers/md/raid1.c
> > > +++ b/drivers/md/raid1.c
> > > @@ -57,19 +57,25 @@ INTERVAL_TREE_DEFINE(struct serial_info, node, sector_t, _subtree_last,
> > > START, LAST, static inline, raid1_rb);
> > >
> > > static int check_and_add_serial(struct md_rdev *rdev, struct r1bio *r1_bio,
> > > - struct serial_info *si, int idx)
> > > + struct serial_info *si)
> > > {
> > > unsigned long flags;
> > > int ret = 0;
> > > sector_t lo = r1_bio->sector;
> > > sector_t hi = lo + r1_bio->sectors - 1;
> > > + int idx = sector_to_idx(r1_bio->sector);
> > > struct serial_in_rdev *serial = &rdev->serial[idx];
> > > + struct serial_info *head_si;
> > >
> > > spin_lock_irqsave(&serial->serial_lock, flags);
> > > /* collision happened */
> > > - if (raid1_rb_iter_first(&serial->serial_rb, lo, hi))
> > > + head_si = raid1_rb_iter_first(&serial->serial_rb, lo, hi);
> > > + if (head_si && head_si != si) {
> > > + si->start = lo;
> > > + si->last = hi;
> > > + list_add_tail(&si->list_node, &head_si->waiters);
> > > ret = -EBUSY;
> > > - else {
> > > + } else if (!head_si) {
> > > si->start = lo;
> > > si->last = hi;
> > > raid1_rb_insert(si, &serial->serial_rb);
> > > @@ -83,19 +89,23 @@ static void wait_for_serialization(struct md_rdev *rdev, struct r1bio *r1_bio)
> > > {
> > > struct mddev *mddev = rdev->mddev;
> > > struct serial_info *si;
> > > - int idx = sector_to_idx(r1_bio->sector);
> > > - struct serial_in_rdev *serial = &rdev->serial[idx];
> > >
> > > if (WARN_ON(!mddev->serial_info_pool))
> > > return;
> > > si = mempool_alloc(mddev->serial_info_pool, GFP_NOIO);
> > > - wait_event(serial->serial_io_wait,
> > > - check_and_add_serial(rdev, r1_bio, si, idx) == 0);
> > > + INIT_LIST_HEAD(&si->waiters);
> > > + INIT_LIST_HEAD(&si->list_node);
> > > + init_completion(&si->ready);
> > > + while (check_and_add_serial(rdev, r1_bio, si)) {
> > > + wait_for_completion(&si->ready);
> > > + reinit_completion(&si->ready);
> > > + }
> > > }
> > >
> > > static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi)
> > > {
> > > struct serial_info *si;
> > > + struct serial_info *first_si;
> > > unsigned long flags;
> > > int found = 0;
> > > struct mddev *mddev = rdev->mddev;
> > > @@ -106,16 +116,25 @@ static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi)
> > > for (si = raid1_rb_iter_first(&serial->serial_rb, lo, hi);
> > > si; si = raid1_rb_iter_next(si, lo, hi)) {
> > > if (si->start == lo && si->last == hi) {
> > > - raid1_rb_remove(si, &serial->serial_rb);
> > > - mempool_free(si, mddev->serial_info_pool);
> > > found = 1;
> > > break;
> > > }
> > > }
> > > if (!found)
> > > WARN(1, "The write IO is not recorded for serialization\n");
> > > + else {
> > > + raid1_rb_remove(si, &serial->serial_rb);
> > > + if (!list_empty(&si->waiters)) {
> > > + first_si = list_first_entry(&si->waiters,
> > > + struct serial_info, list_node);
> > > + list_del_init(&first_si->list_node);
> > > + list_splice_init(&si->waiters, &first_si->waiters);
> > > + raid1_rb_insert(first_si, &serial->serial_rb);
> > > + complete(&first_si->ready);
> > > + }
> > > + mempool_free(si, mddev->serial_info_pool);
> > > + }
> > > spin_unlock_irqrestore(&serial->serial_lock, flags);
> > > - wake_up(&serial->serial_io_wait);
> > > }
> > >
> > > /*
> >
> > --
> > Thansk,
> > Kuai
> >
^ permalink raw reply
* Re: [PATCH 2/2] md/raid1: serialize overlapped io for writemostly disk
From: Xiao Ni @ 2026-02-11 2:44 UTC (permalink / raw)
To: yukuai; +Cc: song, linux-raid, linan666
In-Reply-To: <9bd6581f-289a-4490-af6d-f15589446e1e@fnnas.com>
On Wed, Feb 11, 2026 at 10:32 AM Yu Kuai <yukuai@fnnas.com> wrote:
>
> Hi,
>
> 在 2026/2/6 13:38, Xiao Ni 写道:
> > In behind mode, overlap bios for writemostly device are queued. They
> > In behind mode, bios which overlap the bio from the interval tree
> > need to wait in waitqueue. Those bios will be handled once the in-tree
> > bio finishes. They are waken up and try to get the tree lock. The bio
> > which gets the lock will be handled. So the sequence can't be guaranteed.
> >
> > For example
> > bio1(100,200)
> > bio2(150,200)
> > bio3(150,300)
> > The write sequence of fast device is bio1,bio2,bio3. But the write
> > sequence of slow device is bio1,bio3,bio2. This causes data corruption.
> > Replace waitqueue with a fifo list to guarantee the write sequence.
>
> To be honest, I think this is fine with the respect user won't send overlap
> bios. In this case, bio1 is done in fast disk and pending in slow disk, then
> bio2 will stuck while issuing and waiting for bio1 to return from slow disk.
> So send bio3 in this case is not expected, and if you do you can't guarantee
> the complete order from fast disk as bio2, bio3 as well.
Hi Kuai
In write behind mode, raid1 returns bio1 to the upper layer once the
write on the fast disk finishes. The upper layer (app/filesystem)
thinks that bio1 has finished, while the write of bio1 to the slow
disk is still in progress. So bio2 will not be stuck while issuing, am
I right? If so, bio2 can be submitted to raid1 once the write of bio1
to the fast disk finishes. And bio3 can be submitted to raid1 once the
write of bio2 to fast disk finishes.
Best Regards
Xiao
>
> >
> > Signed-off-by: Xiao Ni <xni@redhat.com>
> > ---
> > drivers/md/md.c | 1 -
> > drivers/md/md.h | 4 +++-
> > drivers/md/raid1.c | 39 +++++++++++++++++++++++++++++----------
> > 3 files changed, 32 insertions(+), 12 deletions(-)
> >
> > diff --git a/drivers/md/md.c b/drivers/md/md.c
> > index 59cd303548de..ab91d17c2d68 100644
> > --- a/drivers/md/md.c
> > +++ b/drivers/md/md.c
> > @@ -188,7 +188,6 @@ static int rdev_init_serial(struct md_rdev *rdev)
> >
> > spin_lock_init(&serial_tmp->serial_lock);
> > serial_tmp->serial_rb = RB_ROOT_CACHED;
> > - init_waitqueue_head(&serial_tmp->serial_io_wait);
> > }
> >
> > rdev->serial = serial;
> > diff --git a/drivers/md/md.h b/drivers/md/md.h
> > index ac84289664cd..64ffbb2efb87 100644
> > --- a/drivers/md/md.h
> > +++ b/drivers/md/md.h
> > @@ -126,7 +126,6 @@ enum sync_action {
> > struct serial_in_rdev {
> > struct rb_root_cached serial_rb;
> > spinlock_t serial_lock;
> > - wait_queue_head_t serial_io_wait;
> > };
> >
> > /*
> > @@ -382,6 +381,9 @@ struct serial_info {
> > sector_t start; /* start sector of rb node */
> > sector_t last; /* end sector of rb node */
> > sector_t _subtree_last; /* highest sector in subtree of rb node */
> > + struct list_head list_node;
> > + struct list_head waiters;
> > + struct completion ready;
> > };
> >
> > /*
> > diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> > index a41b1ec3d695..38c73538d038 100644
> > --- a/drivers/md/raid1.c
> > +++ b/drivers/md/raid1.c
> > @@ -57,19 +57,25 @@ INTERVAL_TREE_DEFINE(struct serial_info, node, sector_t, _subtree_last,
> > START, LAST, static inline, raid1_rb);
> >
> > static int check_and_add_serial(struct md_rdev *rdev, struct r1bio *r1_bio,
> > - struct serial_info *si, int idx)
> > + struct serial_info *si)
> > {
> > unsigned long flags;
> > int ret = 0;
> > sector_t lo = r1_bio->sector;
> > sector_t hi = lo + r1_bio->sectors - 1;
> > + int idx = sector_to_idx(r1_bio->sector);
> > struct serial_in_rdev *serial = &rdev->serial[idx];
> > + struct serial_info *head_si;
> >
> > spin_lock_irqsave(&serial->serial_lock, flags);
> > /* collision happened */
> > - if (raid1_rb_iter_first(&serial->serial_rb, lo, hi))
> > + head_si = raid1_rb_iter_first(&serial->serial_rb, lo, hi);
> > + if (head_si && head_si != si) {
> > + si->start = lo;
> > + si->last = hi;
> > + list_add_tail(&si->list_node, &head_si->waiters);
> > ret = -EBUSY;
> > - else {
> > + } else if (!head_si) {
> > si->start = lo;
> > si->last = hi;
> > raid1_rb_insert(si, &serial->serial_rb);
> > @@ -83,19 +89,23 @@ static void wait_for_serialization(struct md_rdev *rdev, struct r1bio *r1_bio)
> > {
> > struct mddev *mddev = rdev->mddev;
> > struct serial_info *si;
> > - int idx = sector_to_idx(r1_bio->sector);
> > - struct serial_in_rdev *serial = &rdev->serial[idx];
> >
> > if (WARN_ON(!mddev->serial_info_pool))
> > return;
> > si = mempool_alloc(mddev->serial_info_pool, GFP_NOIO);
> > - wait_event(serial->serial_io_wait,
> > - check_and_add_serial(rdev, r1_bio, si, idx) == 0);
> > + INIT_LIST_HEAD(&si->waiters);
> > + INIT_LIST_HEAD(&si->list_node);
> > + init_completion(&si->ready);
> > + while (check_and_add_serial(rdev, r1_bio, si)) {
> > + wait_for_completion(&si->ready);
> > + reinit_completion(&si->ready);
> > + }
> > }
> >
> > static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi)
> > {
> > struct serial_info *si;
> > + struct serial_info *first_si;
> > unsigned long flags;
> > int found = 0;
> > struct mddev *mddev = rdev->mddev;
> > @@ -106,16 +116,25 @@ static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi)
> > for (si = raid1_rb_iter_first(&serial->serial_rb, lo, hi);
> > si; si = raid1_rb_iter_next(si, lo, hi)) {
> > if (si->start == lo && si->last == hi) {
> > - raid1_rb_remove(si, &serial->serial_rb);
> > - mempool_free(si, mddev->serial_info_pool);
> > found = 1;
> > break;
> > }
> > }
> > if (!found)
> > WARN(1, "The write IO is not recorded for serialization\n");
> > + else {
> > + raid1_rb_remove(si, &serial->serial_rb);
> > + if (!list_empty(&si->waiters)) {
> > + first_si = list_first_entry(&si->waiters,
> > + struct serial_info, list_node);
> > + list_del_init(&first_si->list_node);
> > + list_splice_init(&si->waiters, &first_si->waiters);
> > + raid1_rb_insert(first_si, &serial->serial_rb);
> > + complete(&first_si->ready);
> > + }
> > + mempool_free(si, mddev->serial_info_pool);
> > + }
> > spin_unlock_irqrestore(&serial->serial_lock, flags);
> > - wake_up(&serial->serial_io_wait);
> > }
> >
> > /*
>
> --
> Thansk,
> Kuai
>
^ permalink raw reply
* Re: [PATCH 1/2] md/raid1: fix the comparing region of interval tree
From: Xiao Ni @ 2026-02-11 2:35 UTC (permalink / raw)
To: yukuai; +Cc: song, linux-raid, linan666
In-Reply-To: <02c05b44-ee43-44c0-ae39-d1c77d31158f@fnnas.com>
On Wed, Feb 11, 2026 at 10:19 AM Yu Kuai <yukuai@fnnas.com> wrote:
>
> Hi,
>
> 在 2026/2/6 13:38, Xiao Ni 写道:
> > Interval tree uses [start, end] as a region which stores in the tree.
> > In raid1, it uses the wrong end value. For example:
> > bio(A,B) is too big and needs to be split to bio1(A,C-1), bio2(C,B).
> > The region of bio1 is [A,C] and the region of bio2 is [C,B]. So bio1 and
> > bio2 overlap which is not right.
> >
> > Fix this problem by using right end value of the region.
> >
> > Signed-off-by: Xiao Ni <xni@redhat.com>
> > ---
> > drivers/md/raid1.c | 4 ++--
> > 1 file changed, 2 insertions(+), 2 deletions(-)
>
> Perhaps also add a fix tag, with this:
Thanks for the suggestion. I'll add it and send V2
>
> Reviewed-by: Yu Kuai <yukuai@fnnas.com>
>
> >
> > diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> > index 867db18bc3ba..a41b1ec3d695 100644
> > --- a/drivers/md/raid1.c
> > +++ b/drivers/md/raid1.c
> > @@ -62,7 +62,7 @@ static int check_and_add_serial(struct md_rdev *rdev, struct r1bio *r1_bio,
> > unsigned long flags;
> > int ret = 0;
> > sector_t lo = r1_bio->sector;
> > - sector_t hi = lo + r1_bio->sectors;
> > + sector_t hi = lo + r1_bio->sectors - 1;
> > struct serial_in_rdev *serial = &rdev->serial[idx];
> >
> > spin_lock_irqsave(&serial->serial_lock, flags);
> > @@ -453,7 +453,7 @@ static void raid1_end_write_request(struct bio *bio)
> > int mirror = find_bio_disk(r1_bio, bio);
> > struct md_rdev *rdev = conf->mirrors[mirror].rdev;
> > sector_t lo = r1_bio->sector;
> > - sector_t hi = r1_bio->sector + r1_bio->sectors;
> > + sector_t hi = r1_bio->sector + r1_bio->sectors - 1;
> > bool ignore_error = !raid1_should_handle_error(bio) ||
> > (bio->bi_status && bio_op(bio) == REQ_OP_DISCARD);
> >
>
> --
> Thansk,
> Kuai
>
^ permalink raw reply
* Re: [PATCH 2/2] md/raid1: serialize overlapped io for writemostly disk
From: Yu Kuai @ 2026-02-11 2:31 UTC (permalink / raw)
To: Xiao Ni; +Cc: song, linux-raid, linan666, yukuai
In-Reply-To: <20260206053826.37416-3-xni@redhat.com>
Hi,
在 2026/2/6 13:38, Xiao Ni 写道:
> In behind mode, overlap bios for writemostly device are queued. They
> In behind mode, bios which overlap the bio from the interval tree
> need to wait in waitqueue. Those bios will be handled once the in-tree
> bio finishes. They are waken up and try to get the tree lock. The bio
> which gets the lock will be handled. So the sequence can't be guaranteed.
>
> For example
> bio1(100,200)
> bio2(150,200)
> bio3(150,300)
> The write sequence of fast device is bio1,bio2,bio3. But the write
> sequence of slow device is bio1,bio3,bio2. This causes data corruption.
> Replace waitqueue with a fifo list to guarantee the write sequence.
To be honest, I think this is fine with the respect user won't send overlap
bios. In this case, bio1 is done in fast disk and pending in slow disk, then
bio2 will stuck while issuing and waiting for bio1 to return from slow disk.
So send bio3 in this case is not expected, and if you do you can't guarantee
the complete order from fast disk as bio2, bio3 as well.
>
> Signed-off-by: Xiao Ni <xni@redhat.com>
> ---
> drivers/md/md.c | 1 -
> drivers/md/md.h | 4 +++-
> drivers/md/raid1.c | 39 +++++++++++++++++++++++++++++----------
> 3 files changed, 32 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index 59cd303548de..ab91d17c2d68 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -188,7 +188,6 @@ static int rdev_init_serial(struct md_rdev *rdev)
>
> spin_lock_init(&serial_tmp->serial_lock);
> serial_tmp->serial_rb = RB_ROOT_CACHED;
> - init_waitqueue_head(&serial_tmp->serial_io_wait);
> }
>
> rdev->serial = serial;
> diff --git a/drivers/md/md.h b/drivers/md/md.h
> index ac84289664cd..64ffbb2efb87 100644
> --- a/drivers/md/md.h
> +++ b/drivers/md/md.h
> @@ -126,7 +126,6 @@ enum sync_action {
> struct serial_in_rdev {
> struct rb_root_cached serial_rb;
> spinlock_t serial_lock;
> - wait_queue_head_t serial_io_wait;
> };
>
> /*
> @@ -382,6 +381,9 @@ struct serial_info {
> sector_t start; /* start sector of rb node */
> sector_t last; /* end sector of rb node */
> sector_t _subtree_last; /* highest sector in subtree of rb node */
> + struct list_head list_node;
> + struct list_head waiters;
> + struct completion ready;
> };
>
> /*
> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> index a41b1ec3d695..38c73538d038 100644
> --- a/drivers/md/raid1.c
> +++ b/drivers/md/raid1.c
> @@ -57,19 +57,25 @@ INTERVAL_TREE_DEFINE(struct serial_info, node, sector_t, _subtree_last,
> START, LAST, static inline, raid1_rb);
>
> static int check_and_add_serial(struct md_rdev *rdev, struct r1bio *r1_bio,
> - struct serial_info *si, int idx)
> + struct serial_info *si)
> {
> unsigned long flags;
> int ret = 0;
> sector_t lo = r1_bio->sector;
> sector_t hi = lo + r1_bio->sectors - 1;
> + int idx = sector_to_idx(r1_bio->sector);
> struct serial_in_rdev *serial = &rdev->serial[idx];
> + struct serial_info *head_si;
>
> spin_lock_irqsave(&serial->serial_lock, flags);
> /* collision happened */
> - if (raid1_rb_iter_first(&serial->serial_rb, lo, hi))
> + head_si = raid1_rb_iter_first(&serial->serial_rb, lo, hi);
> + if (head_si && head_si != si) {
> + si->start = lo;
> + si->last = hi;
> + list_add_tail(&si->list_node, &head_si->waiters);
> ret = -EBUSY;
> - else {
> + } else if (!head_si) {
> si->start = lo;
> si->last = hi;
> raid1_rb_insert(si, &serial->serial_rb);
> @@ -83,19 +89,23 @@ static void wait_for_serialization(struct md_rdev *rdev, struct r1bio *r1_bio)
> {
> struct mddev *mddev = rdev->mddev;
> struct serial_info *si;
> - int idx = sector_to_idx(r1_bio->sector);
> - struct serial_in_rdev *serial = &rdev->serial[idx];
>
> if (WARN_ON(!mddev->serial_info_pool))
> return;
> si = mempool_alloc(mddev->serial_info_pool, GFP_NOIO);
> - wait_event(serial->serial_io_wait,
> - check_and_add_serial(rdev, r1_bio, si, idx) == 0);
> + INIT_LIST_HEAD(&si->waiters);
> + INIT_LIST_HEAD(&si->list_node);
> + init_completion(&si->ready);
> + while (check_and_add_serial(rdev, r1_bio, si)) {
> + wait_for_completion(&si->ready);
> + reinit_completion(&si->ready);
> + }
> }
>
> static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi)
> {
> struct serial_info *si;
> + struct serial_info *first_si;
> unsigned long flags;
> int found = 0;
> struct mddev *mddev = rdev->mddev;
> @@ -106,16 +116,25 @@ static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi)
> for (si = raid1_rb_iter_first(&serial->serial_rb, lo, hi);
> si; si = raid1_rb_iter_next(si, lo, hi)) {
> if (si->start == lo && si->last == hi) {
> - raid1_rb_remove(si, &serial->serial_rb);
> - mempool_free(si, mddev->serial_info_pool);
> found = 1;
> break;
> }
> }
> if (!found)
> WARN(1, "The write IO is not recorded for serialization\n");
> + else {
> + raid1_rb_remove(si, &serial->serial_rb);
> + if (!list_empty(&si->waiters)) {
> + first_si = list_first_entry(&si->waiters,
> + struct serial_info, list_node);
> + list_del_init(&first_si->list_node);
> + list_splice_init(&si->waiters, &first_si->waiters);
> + raid1_rb_insert(first_si, &serial->serial_rb);
> + complete(&first_si->ready);
> + }
> + mempool_free(si, mddev->serial_info_pool);
> + }
> spin_unlock_irqrestore(&serial->serial_lock, flags);
> - wake_up(&serial->serial_io_wait);
> }
>
> /*
--
Thansk,
Kuai
^ permalink raw reply
* Re: [PATCH 1/2] md/raid1: fix the comparing region of interval tree
From: Yu Kuai @ 2026-02-11 2:18 UTC (permalink / raw)
To: Xiao Ni; +Cc: song, linux-raid, linan666, yukuai
In-Reply-To: <20260206053826.37416-2-xni@redhat.com>
Hi,
在 2026/2/6 13:38, Xiao Ni 写道:
> Interval tree uses [start, end] as a region which stores in the tree.
> In raid1, it uses the wrong end value. For example:
> bio(A,B) is too big and needs to be split to bio1(A,C-1), bio2(C,B).
> The region of bio1 is [A,C] and the region of bio2 is [C,B]. So bio1 and
> bio2 overlap which is not right.
>
> Fix this problem by using right end value of the region.
>
> Signed-off-by: Xiao Ni <xni@redhat.com>
> ---
> drivers/md/raid1.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
Perhaps also add a fix tag, with this:
Reviewed-by: Yu Kuai <yukuai@fnnas.com>
>
> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> index 867db18bc3ba..a41b1ec3d695 100644
> --- a/drivers/md/raid1.c
> +++ b/drivers/md/raid1.c
> @@ -62,7 +62,7 @@ static int check_and_add_serial(struct md_rdev *rdev, struct r1bio *r1_bio,
> unsigned long flags;
> int ret = 0;
> sector_t lo = r1_bio->sector;
> - sector_t hi = lo + r1_bio->sectors;
> + sector_t hi = lo + r1_bio->sectors - 1;
> struct serial_in_rdev *serial = &rdev->serial[idx];
>
> spin_lock_irqsave(&serial->serial_lock, flags);
> @@ -453,7 +453,7 @@ static void raid1_end_write_request(struct bio *bio)
> int mirror = find_bio_disk(r1_bio, bio);
> struct md_rdev *rdev = conf->mirrors[mirror].rdev;
> sector_t lo = r1_bio->sector;
> - sector_t hi = r1_bio->sector + r1_bio->sectors;
> + sector_t hi = r1_bio->sector + r1_bio->sectors - 1;
> bool ignore_error = !raid1_should_handle_error(bio) ||
> (bio->bi_status && bio_op(bio) == REQ_OP_DISCARD);
>
--
Thansk,
Kuai
^ permalink raw reply
* [PATCH v2] md/raid10: fix deadlock with check operation and nowait requests
From: Josh Hunt @ 2026-02-10 16:51 UTC (permalink / raw)
To: song, yukuai, linan122, linux-raid; +Cc: ncroxon, Josh Hunt, stable
When an array check is running it will raise the barrier at which point
normal requests will become blocked and increment the nr_pending value to
signal there is work pending inside of wait_barrier(). NOWAIT requests
do not block and so will return immediately with an error, and additionally
do not increment nr_pending in wait_barrier(). Upstream change
43806c3d5b9b ("raid10: cleanup memleak at raid10_make_request") added a
call to raid_end_bio_io() to fix a memory leak when NOWAIT requests hit
this condition. raid_end_bio_io() eventually calls allow_barrier() and
it will unconditionally do an atomic_dec_and_test(&conf->nr_pending) even
though the corresponding increment on nr_pending didn't happen in the
NOWAIT case.
This can be easily seen by starting a check operation while an application is
doing nowait IO on the same array. This results in a deadlocked state due to
nr_pending value underflowing and so the md resync thread gets stuck waiting
for nr_pending to == 0.
Output of r10conf state of the array when we hit this condition:
crash> struct r10conf.barrier,nr_pending,nr_waiting,nr_queued <addr of r10conf>
barrier = 1,
nr_pending = {
counter = -41
},
nr_waiting = 15,
nr_queued = 0,
Example of md_sync thread stuck waiting on raise_barrier() and other requests
stuck in wait_barrier():
md1_resync
[<0>] raise_barrier+0xce/0x1c0
[<0>] raid10_sync_request+0x1ca/0x1ed0
[<0>] md_do_sync+0x779/0x1110
[<0>] md_thread+0x90/0x160
[<0>] kthread+0xbe/0xf0
[<0>] ret_from_fork+0x34/0x50
[<0>] ret_from_fork_asm+0x1a/0x30
kworker/u1040:2+flush-253:4
[<0>] wait_barrier+0x1de/0x220
[<0>] regular_request_wait+0x30/0x180
[<0>] raid10_make_request+0x261/0x1000
[<0>] md_handle_request+0x13b/0x230
[<0>] __submit_bio+0x107/0x1f0
[<0>] submit_bio_noacct_nocheck+0x16f/0x390
[<0>] ext4_io_submit+0x24/0x40
[<0>] ext4_do_writepages+0x254/0xc80
[<0>] ext4_writepages+0x84/0x120
[<0>] do_writepages+0x7a/0x260
[<0>] __writeback_single_inode+0x3d/0x300
[<0>] writeback_sb_inodes+0x1dd/0x470
[<0>] __writeback_inodes_wb+0x4c/0xe0
[<0>] wb_writeback+0x18b/0x2d0
[<0>] wb_workfn+0x2a1/0x400
[<0>] process_one_work+0x149/0x330
[<0>] worker_thread+0x2d2/0x410
[<0>] kthread+0xbe/0xf0
[<0>] ret_from_fork+0x34/0x50
[<0>] ret_from_fork_asm+0x1a/0x30
Fixes: 43806c3d5b9b ("raid10: cleanup memleak at raid10_make_request")
Cc: stable@vger.kernel.org
Signed-off-by: Josh Hunt <johunt@akamai.com>
---
drivers/md/raid10.c | 40 +++++++++++++++++++++++++++-------------
1 file changed, 27 insertions(+), 13 deletions(-)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 9debb20cf129..b05066dde693 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -68,6 +68,7 @@
*/
static void allow_barrier(struct r10conf *conf);
+static void allow_barrier_nowait(struct r10conf *conf);
static void lower_barrier(struct r10conf *conf);
static int _enough(struct r10conf *conf, int previous, int ignore);
static int enough(struct r10conf *conf, int ignore);
@@ -317,7 +318,7 @@ static void reschedule_retry(struct r10bio *r10_bio)
* operation and are ready to return a success/failure code to the buffer
* cache layer.
*/
-static void raid_end_bio_io(struct r10bio *r10_bio)
+static void raid_end_bio_io(struct r10bio *r10_bio, bool adjust_pending)
{
struct bio *bio = r10_bio->master_bio;
struct r10conf *conf = r10_bio->mddev->private;
@@ -332,7 +333,10 @@ static void raid_end_bio_io(struct r10bio *r10_bio)
* Wake up any possible resync thread that waits for the device
* to go idle.
*/
- allow_barrier(conf);
+ if (adjust_pending)
+ allow_barrier(conf);
+ else
+ allow_barrier_nowait(conf);
free_r10bio(r10_bio);
}
@@ -414,7 +418,7 @@ static void raid10_end_read_request(struct bio *bio)
uptodate = 1;
}
if (uptodate) {
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, true);
rdev_dec_pending(rdev, conf->mddev);
} else {
/*
@@ -446,7 +450,7 @@ static void one_write_done(struct r10bio *r10_bio)
if (test_bit(R10BIO_MadeGood, &r10_bio->state))
reschedule_retry(r10_bio);
else
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, true);
}
}
}
@@ -1030,13 +1034,23 @@ static bool wait_barrier(struct r10conf *conf, bool nowait)
return ret;
}
-static void allow_barrier(struct r10conf *conf)
+static void __allow_barrier(struct r10conf *conf, bool adjust_pending)
{
- if ((atomic_dec_and_test(&conf->nr_pending)) ||
+ if ((adjust_pending && atomic_dec_and_test(&conf->nr_pending)) ||
(conf->array_freeze_pending))
wake_up_barrier(conf);
}
+static void allow_barrier(struct r10conf *conf)
+{
+ __allow_barrier(conf, true);
+}
+
+static void allow_barrier_nowait(struct r10conf *conf)
+{
+ __allow_barrier(conf, false);
+}
+
static void freeze_array(struct r10conf *conf, int extra)
{
/* stop syncio and normal IO and wait for everything to
@@ -1184,7 +1198,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
}
if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, false);
return;
}
@@ -1195,7 +1209,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
mdname(mddev), b,
(unsigned long long)r10_bio->sector);
}
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, true);
return;
}
if (err_rdev)
@@ -1240,7 +1254,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
return;
err_handle:
atomic_dec(&rdev->nr_pending);
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, true);
}
static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio,
@@ -1372,7 +1386,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
sectors = r10_bio->sectors;
if (!regular_request_wait(mddev, conf, bio, sectors)) {
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, false);
return;
}
@@ -1523,7 +1537,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
}
}
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, true);
}
static void __make_request(struct mddev *mddev, struct bio *bio, int sectors)
@@ -2952,7 +2966,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
if (test_bit(R10BIO_WriteError,
&r10_bio->state))
close_write(r10_bio);
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, true);
}
}
}
@@ -2987,7 +3001,7 @@ static void raid10d(struct md_thread *thread)
if (test_bit(R10BIO_WriteError,
&r10_bio->state))
close_write(r10_bio);
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, true);
}
}
--
2.34.1
^ permalink raw reply related
* Re: [PATCH] md/raid10: fix deadlock with check operation and nowait requests
From: Josh Hunt @ 2026-02-10 11:56 UTC (permalink / raw)
To: kernel test robot, song, yukuai, linan122, linux-raid
Cc: oe-kbuild-all, ncroxon, stable
In-Reply-To: <202602101220.J4BofeDD-lkp@intel.com>
On 2/10/26 3:14 AM, kernel test robot wrote:
> !-------------------------------------------------------------------|
> This Message Is From an External Sender
> This message came from outside your organization.
> |-------------------------------------------------------------------!
>
> Hi Josh,
>
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on linus/master]
> [also build test ERROR on v6.19 next-20260209]
> [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://urldefense.com/v3/__https://git-scm.com/docs/git-format-patch*_base_tree_information__;Iw!!GjvTz_vk!QT9JklLw7YgSInuzDS_0EDSnJkZTTG057ef2CiWO2UwIN0aUk9RGNuVtQ6XCy8sTbfadURM$ ]
>
> url: https://urldefense.com/v3/__https://github.com/intel-lab-lkp/linux/commits/Josh-Hunt/md-raid10-fix-deadlock-with-check-operation-and-nowait-requests/20260210-135305__;!!GjvTz_vk!QT9JklLw7YgSInuzDS_0EDSnJkZTTG057ef2CiWO2UwIN0aUk9RGNuVtQ6XCy8sTilUfWlw$
> base: linus/master
> patch link: https://urldefense.com/v3/__https://lore.kernel.org/r/20260210050942.3731656-1-johunt*40akamai.com__;JQ!!GjvTz_vk!QT9JklLw7YgSInuzDS_0EDSnJkZTTG057ef2CiWO2UwIN0aUk9RGNuVtQ6XCy8sT0QqCm3Y$
> patch subject: [PATCH] md/raid10: fix deadlock with check operation and nowait requests
> config: x86_64-rhel-9.4 (https://urldefense.com/v3/__https://download.01.org/0day-ci/archive/20260210/202602101220.J4BofeDD-lkp@intel.com/config__;!!GjvTz_vk!QT9JklLw7YgSInuzDS_0EDSnJkZTTG057ef2CiWO2UwIN0aUk9RGNuVtQ6XCy8sTZp6wg4c$ )
> compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
> reproduce (this is a W=1 build): (https://urldefense.com/v3/__https://download.01.org/0day-ci/archive/20260210/202602101220.J4BofeDD-lkp@intel.com/reproduce__;!!GjvTz_vk!QT9JklLw7YgSInuzDS_0EDSnJkZTTG057ef2CiWO2UwIN0aUk9RGNuVtQ6XCy8sTFU3cM60$ )
>
> 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://urldefense.com/v3/__https://lore.kernel.org/oe-kbuild-all/202602101220.J4BofeDD-lkp@intel.com/__;!!GjvTz_vk!QT9JklLw7YgSInuzDS_0EDSnJkZTTG057ef2CiWO2UwIN0aUk9RGNuVtQ6XCy8sTUPVdYDI$
>
> All errors (new ones prefixed by >>):
>
> drivers/md/raid10.c: In function 'raid10_read_request':
>>> drivers/md/raid10.c:1257:9: error: too few arguments to function 'raid_end_bio_io'
> 1257 | raid_end_bio_io(r10_bio);
> | ^~~~~~~~~~~~~~~
> drivers/md/raid10.c:321:13: note: declared here
> 321 | static void raid_end_bio_io(struct r10bio *r10_bio, bool adjust_pending)
> | ^~~~~~~~~~~~~~~
> drivers/md/raid10.c: In function 'raid10_write_request':
> drivers/md/raid10.c:1540:9: error: too few arguments to function 'raid_end_bio_io'
> 1540 | raid_end_bio_io(r10_bio);
> | ^~~~~~~~~~~~~~~
> drivers/md/raid10.c:321:13: note: declared here
> 321 | static void raid_end_bio_io(struct r10bio *r10_bio, bool adjust_pending)
> | ^~~~~~~~~~~~~~~
>
>
> vim +/raid_end_bio_io +1257 drivers/md/raid10.c
>
> caea3c47ad5152 Guoqing Jiang 2018-12-07 1161
> bb5f1ed70bc3bb Robert LeBlanc 2016-12-05 1162 static void raid10_read_request(struct mddev *mddev, struct bio *bio,
> 820455238366a7 Yu Kuai 2023-06-22 1163 struct r10bio *r10_bio, bool io_accounting)
> ^1da177e4c3f41 Linus Torvalds 2005-04-16 1164 {
> e879a8793f915a NeilBrown 2011-10-11 1165 struct r10conf *conf = mddev->private;
> ^1da177e4c3f41 Linus Torvalds 2005-04-16 1166 struct bio *read_bio;
> d4432c23be957f NeilBrown 2011-07-28 1167 int max_sectors;
> bb5f1ed70bc3bb Robert LeBlanc 2016-12-05 1168 struct md_rdev *rdev;
> 545250f2480911 NeilBrown 2017-04-05 1169 char b[BDEVNAME_SIZE];
> 545250f2480911 NeilBrown 2017-04-05 1170 int slot = r10_bio->read_slot;
> 545250f2480911 NeilBrown 2017-04-05 1171 struct md_rdev *err_rdev = NULL;
> 545250f2480911 NeilBrown 2017-04-05 1172 gfp_t gfp = GFP_NOIO;
> 9b622e2bbcf049 Tomasz Majchrzak 2016-07-28 1173
> 93decc563637c4 Kevin Vigor 2020-11-06 1174 if (slot >= 0 && r10_bio->devs[slot].rdev) {
> 545250f2480911 NeilBrown 2017-04-05 1175 /*
> 545250f2480911 NeilBrown 2017-04-05 1176 * This is an error retry, but we cannot
> 545250f2480911 NeilBrown 2017-04-05 1177 * safely dereference the rdev in the r10_bio,
> 545250f2480911 NeilBrown 2017-04-05 1178 * we must use the one in conf.
> 545250f2480911 NeilBrown 2017-04-05 1179 * If it has already been disconnected (unlikely)
> 545250f2480911 NeilBrown 2017-04-05 1180 * we lose the device name in error messages.
> 545250f2480911 NeilBrown 2017-04-05 1181 */
> 545250f2480911 NeilBrown 2017-04-05 1182 int disk;
> 545250f2480911 NeilBrown 2017-04-05 1183 /*
> 545250f2480911 NeilBrown 2017-04-05 1184 * As we are blocking raid10, it is a little safer to
> 545250f2480911 NeilBrown 2017-04-05 1185 * use __GFP_HIGH.
> 545250f2480911 NeilBrown 2017-04-05 1186 */
> 545250f2480911 NeilBrown 2017-04-05 1187 gfp = GFP_NOIO | __GFP_HIGH;
> 545250f2480911 NeilBrown 2017-04-05 1188
> 545250f2480911 NeilBrown 2017-04-05 1189 disk = r10_bio->devs[slot].devnum;
> a448af25becf4b Yu Kuai 2023-11-25 1190 err_rdev = conf->mirrors[disk].rdev;
> 545250f2480911 NeilBrown 2017-04-05 1191 if (err_rdev)
> 900d156bac2bc4 Christoph Hellwig 2022-07-13 1192 snprintf(b, sizeof(b), "%pg", err_rdev->bdev);
> 545250f2480911 NeilBrown 2017-04-05 1193 else {
> 545250f2480911 NeilBrown 2017-04-05 1194 strcpy(b, "???");
> 545250f2480911 NeilBrown 2017-04-05 1195 /* This never gets dereferenced */
> 545250f2480911 NeilBrown 2017-04-05 1196 err_rdev = r10_bio->devs[slot].rdev;
> 545250f2480911 NeilBrown 2017-04-05 1197 }
> 545250f2480911 NeilBrown 2017-04-05 1198 }
> 856e08e23762df NeilBrown 2011-07-28 1199
> 43806c3d5b9bb7 Nigel Croxon 2025-07-03 1200 if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
> 4e9814d1943b0e Josh Hunt 2026-02-10 1201 raid_end_bio_io(r10_bio, false);
> c9aa889b035fca Vishal Verma 2021-12-21 1202 return;
> 43806c3d5b9bb7 Nigel Croxon 2025-07-03 1203 }
> 43806c3d5b9bb7 Nigel Croxon 2025-07-03 1204
> 96c3fd1f380237 NeilBrown 2011-12-23 1205 rdev = read_balance(conf, r10_bio, &max_sectors);
> 96c3fd1f380237 NeilBrown 2011-12-23 1206 if (!rdev) {
> 545250f2480911 NeilBrown 2017-04-05 1207 if (err_rdev) {
> 545250f2480911 NeilBrown 2017-04-05 1208 pr_crit_ratelimited("md/raid10:%s: %s: unrecoverable I/O read error for block %llu\n",
> 545250f2480911 NeilBrown 2017-04-05 1209 mdname(mddev), b,
> 545250f2480911 NeilBrown 2017-04-05 1210 (unsigned long long)r10_bio->sector);
> 545250f2480911 NeilBrown 2017-04-05 1211 }
> 4e9814d1943b0e Josh Hunt 2026-02-10 1212 raid_end_bio_io(r10_bio, true);
> 5a7bbad27a4103 Christoph Hellwig 2011-09-12 1213 return;
> ^1da177e4c3f41 Linus Torvalds 2005-04-16 1214 }
> 545250f2480911 NeilBrown 2017-04-05 1215 if (err_rdev)
> 913cce5a1e588e Christoph Hellwig 2022-05-12 1216 pr_err_ratelimited("md/raid10:%s: %pg: redirecting sector %llu to another mirror\n",
> 545250f2480911 NeilBrown 2017-04-05 1217 mdname(mddev),
> 913cce5a1e588e Christoph Hellwig 2022-05-12 1218 rdev->bdev,
> 545250f2480911 NeilBrown 2017-04-05 1219 (unsigned long long)r10_bio->sector);
> fc9977dd069e4f NeilBrown 2017-04-05 1220 if (max_sectors < bio_sectors(bio)) {
> e820d55cb99dd9 Guoqing Jiang 2018-12-19 1221 allow_barrier(conf);
> 6fc07785d9b892 Yu Kuai 2025-09-10 1222 bio = bio_submit_split_bioset(bio, max_sectors,
> 6fc07785d9b892 Yu Kuai 2025-09-10 1223 &conf->bio_split);
> c9aa889b035fca Vishal Verma 2021-12-21 1224 wait_barrier(conf, false);
> 6fc07785d9b892 Yu Kuai 2025-09-10 1225 if (!bio) {
> 6fc07785d9b892 Yu Kuai 2025-09-10 1226 set_bit(R10BIO_Returned, &r10_bio->state);
> 4cf58d95290973 John Garry 2024-11-11 1227 goto err_handle;
> 4cf58d95290973 John Garry 2024-11-11 1228 }
> 22f166218f7313 Yu Kuai 2025-09-10 1229
> fc9977dd069e4f NeilBrown 2017-04-05 1230 r10_bio->master_bio = bio;
> fc9977dd069e4f NeilBrown 2017-04-05 1231 r10_bio->sectors = max_sectors;
> fc9977dd069e4f NeilBrown 2017-04-05 1232 }
> 96c3fd1f380237 NeilBrown 2011-12-23 1233 slot = r10_bio->read_slot;
> ^1da177e4c3f41 Linus Torvalds 2005-04-16 1234
> 820455238366a7 Yu Kuai 2023-06-22 1235 if (io_accounting) {
> 820455238366a7 Yu Kuai 2023-06-22 1236 md_account_bio(mddev, &bio);
> 820455238366a7 Yu Kuai 2023-06-22 1237 r10_bio->master_bio = bio;
> 820455238366a7 Yu Kuai 2023-06-22 1238 }
> abfc426d1b2fb2 Christoph Hellwig 2022-02-02 1239 read_bio = bio_alloc_clone(rdev->bdev, bio, gfp, &mddev->bio_set);
> 5fa31c49928139 Zheng Qixing 2025-07-02 1240 read_bio->bi_opf &= ~REQ_NOWAIT;
> ^1da177e4c3f41 Linus Torvalds 2005-04-16 1241
> ^1da177e4c3f41 Linus Torvalds 2005-04-16 1242 r10_bio->devs[slot].bio = read_bio;
> abbf098e6e1e23 NeilBrown 2011-12-23 1243 r10_bio->devs[slot].rdev = rdev;
> ^1da177e4c3f41 Linus Torvalds 2005-04-16 1244
> 4f024f3797c43c Kent Overstreet 2013-10-11 1245 read_bio->bi_iter.bi_sector = r10_bio->devs[slot].addr +
> f8c9e74ff0832f NeilBrown 2012-05-21 1246 choose_data_offset(r10_bio, rdev);
> ^1da177e4c3f41 Linus Torvalds 2005-04-16 1247 read_bio->bi_end_io = raid10_end_read_request;
> 8d3ca83dcf9ca3 NeilBrown 2016-11-18 1248 if (test_bit(FailFast, &rdev->flags) &&
> 8d3ca83dcf9ca3 NeilBrown 2016-11-18 1249 test_bit(R10BIO_FailFast, &r10_bio->state))
> 8d3ca83dcf9ca3 NeilBrown 2016-11-18 1250 read_bio->bi_opf |= MD_FAILFAST;
> ^1da177e4c3f41 Linus Torvalds 2005-04-16 1251 read_bio->bi_private = r10_bio;
> c396b90e502691 Christoph Hellwig 2024-03-03 1252 mddev_trace_remap(mddev, read_bio, r10_bio->sector);
> ed00aabd5eb9fb Christoph Hellwig 2020-07-01 1253 submit_bio_noacct(read_bio);
> 5a7bbad27a4103 Christoph Hellwig 2011-09-12 1254 return;
> 4cf58d95290973 John Garry 2024-11-11 1255 err_handle:
> 4cf58d95290973 John Garry 2024-11-11 1256 atomic_dec(&rdev->nr_pending);
> 4cf58d95290973 John Garry 2024-11-11 @1257 raid_end_bio_io(r10_bio);
> ^1da177e4c3f41 Linus Torvalds 2005-04-16 1258 }
> ^1da177e4c3f41 Linus Torvalds 2005-04-16 1259
>
Apologies. I cherry-picked this from my 6.12.y branch which is where we
hit the issue, but looks like I forgot to build test it. Will send a v2.
Josh
^ permalink raw reply
* Re: [PATCH] md/raid10: fix deadlock with check operation and nowait requests
From: kernel test robot @ 2026-02-10 11:14 UTC (permalink / raw)
To: Josh Hunt, song, yukuai, linan122, linux-raid
Cc: oe-kbuild-all, ncroxon, Josh Hunt, stable
In-Reply-To: <20260210050942.3731656-1-johunt@akamai.com>
Hi Josh,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on v6.19 next-20260209]
[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/Josh-Hunt/md-raid10-fix-deadlock-with-check-operation-and-nowait-requests/20260210-135305
base: linus/master
patch link: https://lore.kernel.org/r/20260210050942.3731656-1-johunt%40akamai.com
patch subject: [PATCH] md/raid10: fix deadlock with check operation and nowait requests
config: x86_64-rhel-9.4 (https://download.01.org/0day-ci/archive/20260210/202602101220.J4BofeDD-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260210/202602101220.J4BofeDD-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/202602101220.J4BofeDD-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/md/raid10.c: In function 'raid10_read_request':
>> drivers/md/raid10.c:1257:9: error: too few arguments to function 'raid_end_bio_io'
1257 | raid_end_bio_io(r10_bio);
| ^~~~~~~~~~~~~~~
drivers/md/raid10.c:321:13: note: declared here
321 | static void raid_end_bio_io(struct r10bio *r10_bio, bool adjust_pending)
| ^~~~~~~~~~~~~~~
drivers/md/raid10.c: In function 'raid10_write_request':
drivers/md/raid10.c:1540:9: error: too few arguments to function 'raid_end_bio_io'
1540 | raid_end_bio_io(r10_bio);
| ^~~~~~~~~~~~~~~
drivers/md/raid10.c:321:13: note: declared here
321 | static void raid_end_bio_io(struct r10bio *r10_bio, bool adjust_pending)
| ^~~~~~~~~~~~~~~
vim +/raid_end_bio_io +1257 drivers/md/raid10.c
caea3c47ad5152 Guoqing Jiang 2018-12-07 1161
bb5f1ed70bc3bb Robert LeBlanc 2016-12-05 1162 static void raid10_read_request(struct mddev *mddev, struct bio *bio,
820455238366a7 Yu Kuai 2023-06-22 1163 struct r10bio *r10_bio, bool io_accounting)
^1da177e4c3f41 Linus Torvalds 2005-04-16 1164 {
e879a8793f915a NeilBrown 2011-10-11 1165 struct r10conf *conf = mddev->private;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1166 struct bio *read_bio;
d4432c23be957f NeilBrown 2011-07-28 1167 int max_sectors;
bb5f1ed70bc3bb Robert LeBlanc 2016-12-05 1168 struct md_rdev *rdev;
545250f2480911 NeilBrown 2017-04-05 1169 char b[BDEVNAME_SIZE];
545250f2480911 NeilBrown 2017-04-05 1170 int slot = r10_bio->read_slot;
545250f2480911 NeilBrown 2017-04-05 1171 struct md_rdev *err_rdev = NULL;
545250f2480911 NeilBrown 2017-04-05 1172 gfp_t gfp = GFP_NOIO;
9b622e2bbcf049 Tomasz Majchrzak 2016-07-28 1173
93decc563637c4 Kevin Vigor 2020-11-06 1174 if (slot >= 0 && r10_bio->devs[slot].rdev) {
545250f2480911 NeilBrown 2017-04-05 1175 /*
545250f2480911 NeilBrown 2017-04-05 1176 * This is an error retry, but we cannot
545250f2480911 NeilBrown 2017-04-05 1177 * safely dereference the rdev in the r10_bio,
545250f2480911 NeilBrown 2017-04-05 1178 * we must use the one in conf.
545250f2480911 NeilBrown 2017-04-05 1179 * If it has already been disconnected (unlikely)
545250f2480911 NeilBrown 2017-04-05 1180 * we lose the device name in error messages.
545250f2480911 NeilBrown 2017-04-05 1181 */
545250f2480911 NeilBrown 2017-04-05 1182 int disk;
545250f2480911 NeilBrown 2017-04-05 1183 /*
545250f2480911 NeilBrown 2017-04-05 1184 * As we are blocking raid10, it is a little safer to
545250f2480911 NeilBrown 2017-04-05 1185 * use __GFP_HIGH.
545250f2480911 NeilBrown 2017-04-05 1186 */
545250f2480911 NeilBrown 2017-04-05 1187 gfp = GFP_NOIO | __GFP_HIGH;
545250f2480911 NeilBrown 2017-04-05 1188
545250f2480911 NeilBrown 2017-04-05 1189 disk = r10_bio->devs[slot].devnum;
a448af25becf4b Yu Kuai 2023-11-25 1190 err_rdev = conf->mirrors[disk].rdev;
545250f2480911 NeilBrown 2017-04-05 1191 if (err_rdev)
900d156bac2bc4 Christoph Hellwig 2022-07-13 1192 snprintf(b, sizeof(b), "%pg", err_rdev->bdev);
545250f2480911 NeilBrown 2017-04-05 1193 else {
545250f2480911 NeilBrown 2017-04-05 1194 strcpy(b, "???");
545250f2480911 NeilBrown 2017-04-05 1195 /* This never gets dereferenced */
545250f2480911 NeilBrown 2017-04-05 1196 err_rdev = r10_bio->devs[slot].rdev;
545250f2480911 NeilBrown 2017-04-05 1197 }
545250f2480911 NeilBrown 2017-04-05 1198 }
856e08e23762df NeilBrown 2011-07-28 1199
43806c3d5b9bb7 Nigel Croxon 2025-07-03 1200 if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
4e9814d1943b0e Josh Hunt 2026-02-10 1201 raid_end_bio_io(r10_bio, false);
c9aa889b035fca Vishal Verma 2021-12-21 1202 return;
43806c3d5b9bb7 Nigel Croxon 2025-07-03 1203 }
43806c3d5b9bb7 Nigel Croxon 2025-07-03 1204
96c3fd1f380237 NeilBrown 2011-12-23 1205 rdev = read_balance(conf, r10_bio, &max_sectors);
96c3fd1f380237 NeilBrown 2011-12-23 1206 if (!rdev) {
545250f2480911 NeilBrown 2017-04-05 1207 if (err_rdev) {
545250f2480911 NeilBrown 2017-04-05 1208 pr_crit_ratelimited("md/raid10:%s: %s: unrecoverable I/O read error for block %llu\n",
545250f2480911 NeilBrown 2017-04-05 1209 mdname(mddev), b,
545250f2480911 NeilBrown 2017-04-05 1210 (unsigned long long)r10_bio->sector);
545250f2480911 NeilBrown 2017-04-05 1211 }
4e9814d1943b0e Josh Hunt 2026-02-10 1212 raid_end_bio_io(r10_bio, true);
5a7bbad27a4103 Christoph Hellwig 2011-09-12 1213 return;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1214 }
545250f2480911 NeilBrown 2017-04-05 1215 if (err_rdev)
913cce5a1e588e Christoph Hellwig 2022-05-12 1216 pr_err_ratelimited("md/raid10:%s: %pg: redirecting sector %llu to another mirror\n",
545250f2480911 NeilBrown 2017-04-05 1217 mdname(mddev),
913cce5a1e588e Christoph Hellwig 2022-05-12 1218 rdev->bdev,
545250f2480911 NeilBrown 2017-04-05 1219 (unsigned long long)r10_bio->sector);
fc9977dd069e4f NeilBrown 2017-04-05 1220 if (max_sectors < bio_sectors(bio)) {
e820d55cb99dd9 Guoqing Jiang 2018-12-19 1221 allow_barrier(conf);
6fc07785d9b892 Yu Kuai 2025-09-10 1222 bio = bio_submit_split_bioset(bio, max_sectors,
6fc07785d9b892 Yu Kuai 2025-09-10 1223 &conf->bio_split);
c9aa889b035fca Vishal Verma 2021-12-21 1224 wait_barrier(conf, false);
6fc07785d9b892 Yu Kuai 2025-09-10 1225 if (!bio) {
6fc07785d9b892 Yu Kuai 2025-09-10 1226 set_bit(R10BIO_Returned, &r10_bio->state);
4cf58d95290973 John Garry 2024-11-11 1227 goto err_handle;
4cf58d95290973 John Garry 2024-11-11 1228 }
22f166218f7313 Yu Kuai 2025-09-10 1229
fc9977dd069e4f NeilBrown 2017-04-05 1230 r10_bio->master_bio = bio;
fc9977dd069e4f NeilBrown 2017-04-05 1231 r10_bio->sectors = max_sectors;
fc9977dd069e4f NeilBrown 2017-04-05 1232 }
96c3fd1f380237 NeilBrown 2011-12-23 1233 slot = r10_bio->read_slot;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1234
820455238366a7 Yu Kuai 2023-06-22 1235 if (io_accounting) {
820455238366a7 Yu Kuai 2023-06-22 1236 md_account_bio(mddev, &bio);
820455238366a7 Yu Kuai 2023-06-22 1237 r10_bio->master_bio = bio;
820455238366a7 Yu Kuai 2023-06-22 1238 }
abfc426d1b2fb2 Christoph Hellwig 2022-02-02 1239 read_bio = bio_alloc_clone(rdev->bdev, bio, gfp, &mddev->bio_set);
5fa31c49928139 Zheng Qixing 2025-07-02 1240 read_bio->bi_opf &= ~REQ_NOWAIT;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1241
^1da177e4c3f41 Linus Torvalds 2005-04-16 1242 r10_bio->devs[slot].bio = read_bio;
abbf098e6e1e23 NeilBrown 2011-12-23 1243 r10_bio->devs[slot].rdev = rdev;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1244
4f024f3797c43c Kent Overstreet 2013-10-11 1245 read_bio->bi_iter.bi_sector = r10_bio->devs[slot].addr +
f8c9e74ff0832f NeilBrown 2012-05-21 1246 choose_data_offset(r10_bio, rdev);
^1da177e4c3f41 Linus Torvalds 2005-04-16 1247 read_bio->bi_end_io = raid10_end_read_request;
8d3ca83dcf9ca3 NeilBrown 2016-11-18 1248 if (test_bit(FailFast, &rdev->flags) &&
8d3ca83dcf9ca3 NeilBrown 2016-11-18 1249 test_bit(R10BIO_FailFast, &r10_bio->state))
8d3ca83dcf9ca3 NeilBrown 2016-11-18 1250 read_bio->bi_opf |= MD_FAILFAST;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1251 read_bio->bi_private = r10_bio;
c396b90e502691 Christoph Hellwig 2024-03-03 1252 mddev_trace_remap(mddev, read_bio, r10_bio->sector);
ed00aabd5eb9fb Christoph Hellwig 2020-07-01 1253 submit_bio_noacct(read_bio);
5a7bbad27a4103 Christoph Hellwig 2011-09-12 1254 return;
4cf58d95290973 John Garry 2024-11-11 1255 err_handle:
4cf58d95290973 John Garry 2024-11-11 1256 atomic_dec(&rdev->nr_pending);
4cf58d95290973 John Garry 2024-11-11 @1257 raid_end_bio_io(r10_bio);
^1da177e4c3f41 Linus Torvalds 2005-04-16 1258 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 1259
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH] md/raid10: fix deadlock with check operation and nowait requests
From: kernel test robot @ 2026-02-10 10:18 UTC (permalink / raw)
To: Josh Hunt, song, yukuai, linan122, linux-raid
Cc: oe-kbuild-all, ncroxon, Josh Hunt, stable
In-Reply-To: <20260210050942.3731656-1-johunt@akamai.com>
Hi Josh,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on v6.19 next-20260209]
[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/Josh-Hunt/md-raid10-fix-deadlock-with-check-operation-and-nowait-requests/20260210-135305
base: linus/master
patch link: https://lore.kernel.org/r/20260210050942.3731656-1-johunt%40akamai.com
patch subject: [PATCH] md/raid10: fix deadlock with check operation and nowait requests
config: m68k-defconfig (https://download.01.org/0day-ci/archive/20260210/202602101850.DC3BeMD5-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260210/202602101850.DC3BeMD5-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/202602101850.DC3BeMD5-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/md/raid10.c: In function 'raid10_read_request':
>> drivers/md/raid10.c:1257:9: error: too few arguments to function 'raid_end_bio_io'; expected 2, have 1
1257 | raid_end_bio_io(r10_bio);
| ^~~~~~~~~~~~~~~
drivers/md/raid10.c:321:13: note: declared here
321 | static void raid_end_bio_io(struct r10bio *r10_bio, bool adjust_pending)
| ^~~~~~~~~~~~~~~
drivers/md/raid10.c: In function 'raid10_write_request':
drivers/md/raid10.c:1540:9: error: too few arguments to function 'raid_end_bio_io'; expected 2, have 1
1540 | raid_end_bio_io(r10_bio);
| ^~~~~~~~~~~~~~~
drivers/md/raid10.c:321:13: note: declared here
321 | static void raid_end_bio_io(struct r10bio *r10_bio, bool adjust_pending)
| ^~~~~~~~~~~~~~~
vim +/raid_end_bio_io +1257 drivers/md/raid10.c
caea3c47ad5152 Guoqing Jiang 2018-12-07 1161
bb5f1ed70bc3bb Robert LeBlanc 2016-12-05 1162 static void raid10_read_request(struct mddev *mddev, struct bio *bio,
820455238366a7 Yu Kuai 2023-06-22 1163 struct r10bio *r10_bio, bool io_accounting)
^1da177e4c3f41 Linus Torvalds 2005-04-16 1164 {
e879a8793f915a NeilBrown 2011-10-11 1165 struct r10conf *conf = mddev->private;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1166 struct bio *read_bio;
d4432c23be957f NeilBrown 2011-07-28 1167 int max_sectors;
bb5f1ed70bc3bb Robert LeBlanc 2016-12-05 1168 struct md_rdev *rdev;
545250f2480911 NeilBrown 2017-04-05 1169 char b[BDEVNAME_SIZE];
545250f2480911 NeilBrown 2017-04-05 1170 int slot = r10_bio->read_slot;
545250f2480911 NeilBrown 2017-04-05 1171 struct md_rdev *err_rdev = NULL;
545250f2480911 NeilBrown 2017-04-05 1172 gfp_t gfp = GFP_NOIO;
9b622e2bbcf049 Tomasz Majchrzak 2016-07-28 1173
93decc563637c4 Kevin Vigor 2020-11-06 1174 if (slot >= 0 && r10_bio->devs[slot].rdev) {
545250f2480911 NeilBrown 2017-04-05 1175 /*
545250f2480911 NeilBrown 2017-04-05 1176 * This is an error retry, but we cannot
545250f2480911 NeilBrown 2017-04-05 1177 * safely dereference the rdev in the r10_bio,
545250f2480911 NeilBrown 2017-04-05 1178 * we must use the one in conf.
545250f2480911 NeilBrown 2017-04-05 1179 * If it has already been disconnected (unlikely)
545250f2480911 NeilBrown 2017-04-05 1180 * we lose the device name in error messages.
545250f2480911 NeilBrown 2017-04-05 1181 */
545250f2480911 NeilBrown 2017-04-05 1182 int disk;
545250f2480911 NeilBrown 2017-04-05 1183 /*
545250f2480911 NeilBrown 2017-04-05 1184 * As we are blocking raid10, it is a little safer to
545250f2480911 NeilBrown 2017-04-05 1185 * use __GFP_HIGH.
545250f2480911 NeilBrown 2017-04-05 1186 */
545250f2480911 NeilBrown 2017-04-05 1187 gfp = GFP_NOIO | __GFP_HIGH;
545250f2480911 NeilBrown 2017-04-05 1188
545250f2480911 NeilBrown 2017-04-05 1189 disk = r10_bio->devs[slot].devnum;
a448af25becf4b Yu Kuai 2023-11-25 1190 err_rdev = conf->mirrors[disk].rdev;
545250f2480911 NeilBrown 2017-04-05 1191 if (err_rdev)
900d156bac2bc4 Christoph Hellwig 2022-07-13 1192 snprintf(b, sizeof(b), "%pg", err_rdev->bdev);
545250f2480911 NeilBrown 2017-04-05 1193 else {
545250f2480911 NeilBrown 2017-04-05 1194 strcpy(b, "???");
545250f2480911 NeilBrown 2017-04-05 1195 /* This never gets dereferenced */
545250f2480911 NeilBrown 2017-04-05 1196 err_rdev = r10_bio->devs[slot].rdev;
545250f2480911 NeilBrown 2017-04-05 1197 }
545250f2480911 NeilBrown 2017-04-05 1198 }
856e08e23762df NeilBrown 2011-07-28 1199
43806c3d5b9bb7 Nigel Croxon 2025-07-03 1200 if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
4e9814d1943b0e Josh Hunt 2026-02-10 1201 raid_end_bio_io(r10_bio, false);
c9aa889b035fca Vishal Verma 2021-12-21 1202 return;
43806c3d5b9bb7 Nigel Croxon 2025-07-03 1203 }
43806c3d5b9bb7 Nigel Croxon 2025-07-03 1204
96c3fd1f380237 NeilBrown 2011-12-23 1205 rdev = read_balance(conf, r10_bio, &max_sectors);
96c3fd1f380237 NeilBrown 2011-12-23 1206 if (!rdev) {
545250f2480911 NeilBrown 2017-04-05 1207 if (err_rdev) {
545250f2480911 NeilBrown 2017-04-05 1208 pr_crit_ratelimited("md/raid10:%s: %s: unrecoverable I/O read error for block %llu\n",
545250f2480911 NeilBrown 2017-04-05 1209 mdname(mddev), b,
545250f2480911 NeilBrown 2017-04-05 1210 (unsigned long long)r10_bio->sector);
545250f2480911 NeilBrown 2017-04-05 1211 }
4e9814d1943b0e Josh Hunt 2026-02-10 1212 raid_end_bio_io(r10_bio, true);
5a7bbad27a4103 Christoph Hellwig 2011-09-12 1213 return;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1214 }
545250f2480911 NeilBrown 2017-04-05 1215 if (err_rdev)
913cce5a1e588e Christoph Hellwig 2022-05-12 1216 pr_err_ratelimited("md/raid10:%s: %pg: redirecting sector %llu to another mirror\n",
545250f2480911 NeilBrown 2017-04-05 1217 mdname(mddev),
913cce5a1e588e Christoph Hellwig 2022-05-12 1218 rdev->bdev,
545250f2480911 NeilBrown 2017-04-05 1219 (unsigned long long)r10_bio->sector);
fc9977dd069e4f NeilBrown 2017-04-05 1220 if (max_sectors < bio_sectors(bio)) {
e820d55cb99dd9 Guoqing Jiang 2018-12-19 1221 allow_barrier(conf);
6fc07785d9b892 Yu Kuai 2025-09-10 1222 bio = bio_submit_split_bioset(bio, max_sectors,
6fc07785d9b892 Yu Kuai 2025-09-10 1223 &conf->bio_split);
c9aa889b035fca Vishal Verma 2021-12-21 1224 wait_barrier(conf, false);
6fc07785d9b892 Yu Kuai 2025-09-10 1225 if (!bio) {
6fc07785d9b892 Yu Kuai 2025-09-10 1226 set_bit(R10BIO_Returned, &r10_bio->state);
4cf58d95290973 John Garry 2024-11-11 1227 goto err_handle;
4cf58d95290973 John Garry 2024-11-11 1228 }
22f166218f7313 Yu Kuai 2025-09-10 1229
fc9977dd069e4f NeilBrown 2017-04-05 1230 r10_bio->master_bio = bio;
fc9977dd069e4f NeilBrown 2017-04-05 1231 r10_bio->sectors = max_sectors;
fc9977dd069e4f NeilBrown 2017-04-05 1232 }
96c3fd1f380237 NeilBrown 2011-12-23 1233 slot = r10_bio->read_slot;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1234
820455238366a7 Yu Kuai 2023-06-22 1235 if (io_accounting) {
820455238366a7 Yu Kuai 2023-06-22 1236 md_account_bio(mddev, &bio);
820455238366a7 Yu Kuai 2023-06-22 1237 r10_bio->master_bio = bio;
820455238366a7 Yu Kuai 2023-06-22 1238 }
abfc426d1b2fb2 Christoph Hellwig 2022-02-02 1239 read_bio = bio_alloc_clone(rdev->bdev, bio, gfp, &mddev->bio_set);
5fa31c49928139 Zheng Qixing 2025-07-02 1240 read_bio->bi_opf &= ~REQ_NOWAIT;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1241
^1da177e4c3f41 Linus Torvalds 2005-04-16 1242 r10_bio->devs[slot].bio = read_bio;
abbf098e6e1e23 NeilBrown 2011-12-23 1243 r10_bio->devs[slot].rdev = rdev;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1244
4f024f3797c43c Kent Overstreet 2013-10-11 1245 read_bio->bi_iter.bi_sector = r10_bio->devs[slot].addr +
f8c9e74ff0832f NeilBrown 2012-05-21 1246 choose_data_offset(r10_bio, rdev);
^1da177e4c3f41 Linus Torvalds 2005-04-16 1247 read_bio->bi_end_io = raid10_end_read_request;
8d3ca83dcf9ca3 NeilBrown 2016-11-18 1248 if (test_bit(FailFast, &rdev->flags) &&
8d3ca83dcf9ca3 NeilBrown 2016-11-18 1249 test_bit(R10BIO_FailFast, &r10_bio->state))
8d3ca83dcf9ca3 NeilBrown 2016-11-18 1250 read_bio->bi_opf |= MD_FAILFAST;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1251 read_bio->bi_private = r10_bio;
c396b90e502691 Christoph Hellwig 2024-03-03 1252 mddev_trace_remap(mddev, read_bio, r10_bio->sector);
ed00aabd5eb9fb Christoph Hellwig 2020-07-01 1253 submit_bio_noacct(read_bio);
5a7bbad27a4103 Christoph Hellwig 2011-09-12 1254 return;
4cf58d95290973 John Garry 2024-11-11 1255 err_handle:
4cf58d95290973 John Garry 2024-11-11 1256 atomic_dec(&rdev->nr_pending);
4cf58d95290973 John Garry 2024-11-11 @1257 raid_end_bio_io(r10_bio);
^1da177e4c3f41 Linus Torvalds 2005-04-16 1258 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 1259
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH] md/raid10: fix deadlock with check operation and nowait requests
From: kernel test robot @ 2026-02-10 10:17 UTC (permalink / raw)
To: Josh Hunt, song, yukuai, linan122, linux-raid
Cc: oe-kbuild-all, ncroxon, Josh Hunt, stable
In-Reply-To: <20260210050942.3731656-1-johunt@akamai.com>
Hi Josh,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on v6.19 next-20260209]
[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/Josh-Hunt/md-raid10-fix-deadlock-with-check-operation-and-nowait-requests/20260210-135305
base: linus/master
patch link: https://lore.kernel.org/r/20260210050942.3731656-1-johunt%40akamai.com
patch subject: [PATCH] md/raid10: fix deadlock with check operation and nowait requests
config: nios2-allmodconfig (https://download.01.org/0day-ci/archive/20260210/202602101844.0pRyZv4D-lkp@intel.com/config)
compiler: nios2-linux-gcc (GCC) 11.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260210/202602101844.0pRyZv4D-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/202602101844.0pRyZv4D-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/md/raid10.c: In function 'raid10_read_request':
>> drivers/md/raid10.c:1257:9: error: too few arguments to function 'raid_end_bio_io'
1257 | raid_end_bio_io(r10_bio);
| ^~~~~~~~~~~~~~~
drivers/md/raid10.c:321:13: note: declared here
321 | static void raid_end_bio_io(struct r10bio *r10_bio, bool adjust_pending)
| ^~~~~~~~~~~~~~~
drivers/md/raid10.c: In function 'raid10_write_request':
drivers/md/raid10.c:1540:9: error: too few arguments to function 'raid_end_bio_io'
1540 | raid_end_bio_io(r10_bio);
| ^~~~~~~~~~~~~~~
drivers/md/raid10.c:321:13: note: declared here
321 | static void raid_end_bio_io(struct r10bio *r10_bio, bool adjust_pending)
| ^~~~~~~~~~~~~~~
vim +/raid_end_bio_io +1257 drivers/md/raid10.c
caea3c47ad5152 Guoqing Jiang 2018-12-07 1161
bb5f1ed70bc3bb Robert LeBlanc 2016-12-05 1162 static void raid10_read_request(struct mddev *mddev, struct bio *bio,
820455238366a7 Yu Kuai 2023-06-22 1163 struct r10bio *r10_bio, bool io_accounting)
^1da177e4c3f41 Linus Torvalds 2005-04-16 1164 {
e879a8793f915a NeilBrown 2011-10-11 1165 struct r10conf *conf = mddev->private;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1166 struct bio *read_bio;
d4432c23be957f NeilBrown 2011-07-28 1167 int max_sectors;
bb5f1ed70bc3bb Robert LeBlanc 2016-12-05 1168 struct md_rdev *rdev;
545250f2480911 NeilBrown 2017-04-05 1169 char b[BDEVNAME_SIZE];
545250f2480911 NeilBrown 2017-04-05 1170 int slot = r10_bio->read_slot;
545250f2480911 NeilBrown 2017-04-05 1171 struct md_rdev *err_rdev = NULL;
545250f2480911 NeilBrown 2017-04-05 1172 gfp_t gfp = GFP_NOIO;
9b622e2bbcf049 Tomasz Majchrzak 2016-07-28 1173
93decc563637c4 Kevin Vigor 2020-11-06 1174 if (slot >= 0 && r10_bio->devs[slot].rdev) {
545250f2480911 NeilBrown 2017-04-05 1175 /*
545250f2480911 NeilBrown 2017-04-05 1176 * This is an error retry, but we cannot
545250f2480911 NeilBrown 2017-04-05 1177 * safely dereference the rdev in the r10_bio,
545250f2480911 NeilBrown 2017-04-05 1178 * we must use the one in conf.
545250f2480911 NeilBrown 2017-04-05 1179 * If it has already been disconnected (unlikely)
545250f2480911 NeilBrown 2017-04-05 1180 * we lose the device name in error messages.
545250f2480911 NeilBrown 2017-04-05 1181 */
545250f2480911 NeilBrown 2017-04-05 1182 int disk;
545250f2480911 NeilBrown 2017-04-05 1183 /*
545250f2480911 NeilBrown 2017-04-05 1184 * As we are blocking raid10, it is a little safer to
545250f2480911 NeilBrown 2017-04-05 1185 * use __GFP_HIGH.
545250f2480911 NeilBrown 2017-04-05 1186 */
545250f2480911 NeilBrown 2017-04-05 1187 gfp = GFP_NOIO | __GFP_HIGH;
545250f2480911 NeilBrown 2017-04-05 1188
545250f2480911 NeilBrown 2017-04-05 1189 disk = r10_bio->devs[slot].devnum;
a448af25becf4b Yu Kuai 2023-11-25 1190 err_rdev = conf->mirrors[disk].rdev;
545250f2480911 NeilBrown 2017-04-05 1191 if (err_rdev)
900d156bac2bc4 Christoph Hellwig 2022-07-13 1192 snprintf(b, sizeof(b), "%pg", err_rdev->bdev);
545250f2480911 NeilBrown 2017-04-05 1193 else {
545250f2480911 NeilBrown 2017-04-05 1194 strcpy(b, "???");
545250f2480911 NeilBrown 2017-04-05 1195 /* This never gets dereferenced */
545250f2480911 NeilBrown 2017-04-05 1196 err_rdev = r10_bio->devs[slot].rdev;
545250f2480911 NeilBrown 2017-04-05 1197 }
545250f2480911 NeilBrown 2017-04-05 1198 }
856e08e23762df NeilBrown 2011-07-28 1199
43806c3d5b9bb7 Nigel Croxon 2025-07-03 1200 if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
4e9814d1943b0e Josh Hunt 2026-02-10 1201 raid_end_bio_io(r10_bio, false);
c9aa889b035fca Vishal Verma 2021-12-21 1202 return;
43806c3d5b9bb7 Nigel Croxon 2025-07-03 1203 }
43806c3d5b9bb7 Nigel Croxon 2025-07-03 1204
96c3fd1f380237 NeilBrown 2011-12-23 1205 rdev = read_balance(conf, r10_bio, &max_sectors);
96c3fd1f380237 NeilBrown 2011-12-23 1206 if (!rdev) {
545250f2480911 NeilBrown 2017-04-05 1207 if (err_rdev) {
545250f2480911 NeilBrown 2017-04-05 1208 pr_crit_ratelimited("md/raid10:%s: %s: unrecoverable I/O read error for block %llu\n",
545250f2480911 NeilBrown 2017-04-05 1209 mdname(mddev), b,
545250f2480911 NeilBrown 2017-04-05 1210 (unsigned long long)r10_bio->sector);
545250f2480911 NeilBrown 2017-04-05 1211 }
4e9814d1943b0e Josh Hunt 2026-02-10 1212 raid_end_bio_io(r10_bio, true);
5a7bbad27a4103 Christoph Hellwig 2011-09-12 1213 return;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1214 }
545250f2480911 NeilBrown 2017-04-05 1215 if (err_rdev)
913cce5a1e588e Christoph Hellwig 2022-05-12 1216 pr_err_ratelimited("md/raid10:%s: %pg: redirecting sector %llu to another mirror\n",
545250f2480911 NeilBrown 2017-04-05 1217 mdname(mddev),
913cce5a1e588e Christoph Hellwig 2022-05-12 1218 rdev->bdev,
545250f2480911 NeilBrown 2017-04-05 1219 (unsigned long long)r10_bio->sector);
fc9977dd069e4f NeilBrown 2017-04-05 1220 if (max_sectors < bio_sectors(bio)) {
e820d55cb99dd9 Guoqing Jiang 2018-12-19 1221 allow_barrier(conf);
6fc07785d9b892 Yu Kuai 2025-09-10 1222 bio = bio_submit_split_bioset(bio, max_sectors,
6fc07785d9b892 Yu Kuai 2025-09-10 1223 &conf->bio_split);
c9aa889b035fca Vishal Verma 2021-12-21 1224 wait_barrier(conf, false);
6fc07785d9b892 Yu Kuai 2025-09-10 1225 if (!bio) {
6fc07785d9b892 Yu Kuai 2025-09-10 1226 set_bit(R10BIO_Returned, &r10_bio->state);
4cf58d95290973 John Garry 2024-11-11 1227 goto err_handle;
4cf58d95290973 John Garry 2024-11-11 1228 }
22f166218f7313 Yu Kuai 2025-09-10 1229
fc9977dd069e4f NeilBrown 2017-04-05 1230 r10_bio->master_bio = bio;
fc9977dd069e4f NeilBrown 2017-04-05 1231 r10_bio->sectors = max_sectors;
fc9977dd069e4f NeilBrown 2017-04-05 1232 }
96c3fd1f380237 NeilBrown 2011-12-23 1233 slot = r10_bio->read_slot;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1234
820455238366a7 Yu Kuai 2023-06-22 1235 if (io_accounting) {
820455238366a7 Yu Kuai 2023-06-22 1236 md_account_bio(mddev, &bio);
820455238366a7 Yu Kuai 2023-06-22 1237 r10_bio->master_bio = bio;
820455238366a7 Yu Kuai 2023-06-22 1238 }
abfc426d1b2fb2 Christoph Hellwig 2022-02-02 1239 read_bio = bio_alloc_clone(rdev->bdev, bio, gfp, &mddev->bio_set);
5fa31c49928139 Zheng Qixing 2025-07-02 1240 read_bio->bi_opf &= ~REQ_NOWAIT;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1241
^1da177e4c3f41 Linus Torvalds 2005-04-16 1242 r10_bio->devs[slot].bio = read_bio;
abbf098e6e1e23 NeilBrown 2011-12-23 1243 r10_bio->devs[slot].rdev = rdev;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1244
4f024f3797c43c Kent Overstreet 2013-10-11 1245 read_bio->bi_iter.bi_sector = r10_bio->devs[slot].addr +
f8c9e74ff0832f NeilBrown 2012-05-21 1246 choose_data_offset(r10_bio, rdev);
^1da177e4c3f41 Linus Torvalds 2005-04-16 1247 read_bio->bi_end_io = raid10_end_read_request;
8d3ca83dcf9ca3 NeilBrown 2016-11-18 1248 if (test_bit(FailFast, &rdev->flags) &&
8d3ca83dcf9ca3 NeilBrown 2016-11-18 1249 test_bit(R10BIO_FailFast, &r10_bio->state))
8d3ca83dcf9ca3 NeilBrown 2016-11-18 1250 read_bio->bi_opf |= MD_FAILFAST;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1251 read_bio->bi_private = r10_bio;
c396b90e502691 Christoph Hellwig 2024-03-03 1252 mddev_trace_remap(mddev, read_bio, r10_bio->sector);
ed00aabd5eb9fb Christoph Hellwig 2020-07-01 1253 submit_bio_noacct(read_bio);
5a7bbad27a4103 Christoph Hellwig 2011-09-12 1254 return;
4cf58d95290973 John Garry 2024-11-11 1255 err_handle:
4cf58d95290973 John Garry 2024-11-11 1256 atomic_dec(&rdev->nr_pending);
4cf58d95290973 John Garry 2024-11-11 @1257 raid_end_bio_io(r10_bio);
^1da177e4c3f41 Linus Torvalds 2005-04-16 1258 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 1259
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [PATCH] md: suppress spurious superblock update error message for dm-raid
From: Chen Cheng @ 2026-02-10 13:38 UTC (permalink / raw)
To: linux-raid; +Cc: linux-kernel, pmenzel, tj.iam.tj, Chen Cheng
dm-raid has external metadata management (mddev->external = 1) and
no persistent superblock (mddev->persistent = 0). For these arrays,
there's no superblock to update, so the error message is spurious.
The error appears as:
[ 123.456789] md_update_sb: can't update sb for read-only array md0
Link: https://lore.kernel.org/all/20260128082430.96788-1-tj.iam.tj@proton.me/
Fixes: 6a5cb53aaa1d ("md: don't ignore read-only array in md_update_sb()")
Signed-off-by: Chen Cheng <chencheng@fnnas.com>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
---
drivers/md/md.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 6d73f6e196a..e30b658641e 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -2790,7 +2790,9 @@ void md_update_sb(struct mddev *mddev, int force_change)
if (!md_is_rdwr(mddev)) {
if (force_change)
set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
- pr_err("%s: can't update sb for read-only array %s\n", __func__, mdname(mddev));
+ if (!mddev_is_dm(mddev))
+ pr_err_ratelimited("%s: can't update sb for read-only array %s\n",
+ __func__, mdname(mddev));
return;
}
--
2.51.0
^ permalink raw reply related
* Re: [PATCH] md: suppress spurious superblock update warning for dm-raid
From: Paul Menzel @ 2026-02-10 7:49 UTC (permalink / raw)
To: chencheng; +Cc: song, yukuai, linux-raid, linux-kernel
In-Reply-To: <20260210124114.169207-1-chencheng@fnnas.com>
Dear Chen,
Thank you for your patch.
Am 10.02.26 um 13:41 schrieb chencheng:
> dm-raid have external metadata management (mddev->external = 1) and
> no persistent superblock (mddev->persistent = 0). For these arrays,
> there's no superblock to update, so the warning is spurious.
Please paste the warning.
Please also add a Fixes: tag.
> Signed-off-by: chencheng <chencheng@fnnas.com>
Would Chen Cheng be the official (transcribed) spelling of your name. If
you yes, it’d be great, if you updated it:
git config --global user.name "Chen Cheng"
git commit --amend -s --author="Chen Cheng <chencheng@fnnas.com>"
> ---
> drivers/md/md.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index 6d73f6e196a..e30b658641e 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -2790,7 +2790,9 @@ void md_update_sb(struct mddev *mddev, int force_change)
> if (!md_is_rdwr(mddev)) {
> if (force_change)
> set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
> - pr_err("%s: can't update sb for read-only array %s\n", __func__, mdname(mddev));
> + if (!mddev_is_dm(mddev))
> + pr_err_ratelimited("%s: can't update sb for read-only array %s\n",
> + __func__, mdname(mddev));
(It looks like it’s an error level message and not a warning level message.)
> return;
> }
With the commit message suggestions addressed, feel free to add:
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Kind regards,
Paul
^ permalink raw reply
* [PATCH] md: suppress spurious superblock update warning for dm-raid
From: chencheng @ 2026-02-10 12:41 UTC (permalink / raw)
To: song, yukuai, linux-raid, linux-kernel; +Cc: chencheng
dm-raid have external metadata management (mddev->external = 1) and
no persistent superblock (mddev->persistent = 0). For these arrays,
there's no superblock to update, so the warning is spurious.
Signed-off-by: chencheng <chencheng@fnnas.com>
---
drivers/md/md.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 6d73f6e196a..e30b658641e 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -2790,7 +2790,9 @@ void md_update_sb(struct mddev *mddev, int force_change)
if (!md_is_rdwr(mddev)) {
if (force_change)
set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
- pr_err("%s: can't update sb for read-only array %s\n", __func__, mdname(mddev));
+ if (!mddev_is_dm(mddev))
+ pr_err_ratelimited("%s: can't update sb for read-only array %s\n",
+ __func__, mdname(mddev));
return;
}
--
2.51.0
^ permalink raw reply related
* [PATCH] md/raid10: fix deadlock with check operation and nowait requests
From: Josh Hunt @ 2026-02-10 5:09 UTC (permalink / raw)
To: song, yukuai, linan122, linux-raid; +Cc: ncroxon, Josh Hunt, stable
When an array check is running it will raise the barrier at which point
normal requests will become blocked and increment the nr_pending value to
signal there is work pending inside of wait_barrier(). NOWAIT requests
do not block and so will return immediately with an error, and additionally
do not increment nr_pending in wait_barrier(). Upstream change
43806c3d5b9b ("raid10: cleanup memleak at raid10_make_request") added a
call to raid_end_bio_io() to fix a memory leak when NOWAIT requests hit
this condition. raid_end_bio_io() eventually calls allow_barrier() and
it will unconditionally do an atomic_dec_and_test(&conf->nr_pending) even
though the corresponding increment on nr_pending didn't happen in the
NOWAIT case.
This can be easily seen by starting a check operation while an application
is doing nowait IO on the same array. This results in a deadlocked state
due to nr_pending value underflowing and so the md resync thread gets
stuck waiting for nr_pending to == 0.
Output of r10conf state of the array when we hit this condition:
crash> struct r10conf.barrier,nr_pending,nr_waiting,nr_queued <addr of r10conf>
barrier = 1,
nr_pending = {
counter = -41
},
nr_waiting = 15,
nr_queued = 0,
Example of md_sync thread stuck waiting on raise_barrier() and other
requests stuck in wait_barrier():
md1_resync
[<0>] raise_barrier+0xce/0x1c0
[<0>] raid10_sync_request+0x1ca/0x1ed0
[<0>] md_do_sync+0x779/0x1110
[<0>] md_thread+0x90/0x160
[<0>] kthread+0xbe/0xf0
[<0>] ret_from_fork+0x34/0x50
[<0>] ret_from_fork_asm+0x1a/0x30
kworker/u1040:2+flush-253:4
[<0>] wait_barrier+0x1de/0x220
[<0>] regular_request_wait+0x30/0x180
[<0>] raid10_make_request+0x261/0x1000
[<0>] md_handle_request+0x13b/0x230
[<0>] __submit_bio+0x107/0x1f0
[<0>] submit_bio_noacct_nocheck+0x16f/0x390
[<0>] ext4_io_submit+0x24/0x40
[<0>] ext4_do_writepages+0x254/0xc80
[<0>] ext4_writepages+0x84/0x120
[<0>] do_writepages+0x7a/0x260
[<0>] __writeback_single_inode+0x3d/0x300
[<0>] writeback_sb_inodes+0x1dd/0x470
[<0>] __writeback_inodes_wb+0x4c/0xe0
[<0>] wb_writeback+0x18b/0x2d0
[<0>] wb_workfn+0x2a1/0x400
[<0>] process_one_work+0x149/0x330
[<0>] worker_thread+0x2d2/0x410
[<0>] kthread+0xbe/0xf0
[<0>] ret_from_fork+0x34/0x50
[<0>] ret_from_fork_asm+0x1a/0x30
Fixes: 43806c3d5b9b ("raid10: cleanup memleak at raid10_make_request")
Cc: stable@vger.kernel.org
Signed-off-by: Josh Hunt <johunt@akamai.com>
---
drivers/md/raid10.c | 36 +++++++++++++++++++++++++-----------
1 file changed, 25 insertions(+), 11 deletions(-)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 9debb20cf129..184b5b3906d1 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -68,6 +68,7 @@
*/
static void allow_barrier(struct r10conf *conf);
+static void allow_barrier_nowait(struct r10conf *conf);
static void lower_barrier(struct r10conf *conf);
static int _enough(struct r10conf *conf, int previous, int ignore);
static int enough(struct r10conf *conf, int ignore);
@@ -317,7 +318,7 @@ static void reschedule_retry(struct r10bio *r10_bio)
* operation and are ready to return a success/failure code to the buffer
* cache layer.
*/
-static void raid_end_bio_io(struct r10bio *r10_bio)
+static void raid_end_bio_io(struct r10bio *r10_bio, bool adjust_pending)
{
struct bio *bio = r10_bio->master_bio;
struct r10conf *conf = r10_bio->mddev->private;
@@ -332,7 +333,10 @@ static void raid_end_bio_io(struct r10bio *r10_bio)
* Wake up any possible resync thread that waits for the device
* to go idle.
*/
- allow_barrier(conf);
+ if (adjust_pending)
+ allow_barrier(conf);
+ else
+ allow_barrier_nowait(conf);
free_r10bio(r10_bio);
}
@@ -414,7 +418,7 @@ static void raid10_end_read_request(struct bio *bio)
uptodate = 1;
}
if (uptodate) {
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, true);
rdev_dec_pending(rdev, conf->mddev);
} else {
/*
@@ -446,7 +450,7 @@ static void one_write_done(struct r10bio *r10_bio)
if (test_bit(R10BIO_MadeGood, &r10_bio->state))
reschedule_retry(r10_bio);
else
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, true);
}
}
}
@@ -1030,13 +1034,23 @@ static bool wait_barrier(struct r10conf *conf, bool nowait)
return ret;
}
-static void allow_barrier(struct r10conf *conf)
+static void __allow_barrier(struct r10conf *conf, bool adjust_pending)
{
- if ((atomic_dec_and_test(&conf->nr_pending)) ||
+ if ((adjust_pending && atomic_dec_and_test(&conf->nr_pending)) ||
(conf->array_freeze_pending))
wake_up_barrier(conf);
}
+static void allow_barrier(struct r10conf *conf)
+{
+ __allow_barrier(conf, true);
+}
+
+static void allow_barrier_nowait(struct r10conf *conf)
+{
+ __allow_barrier(conf, false);
+}
+
static void freeze_array(struct r10conf *conf, int extra)
{
/* stop syncio and normal IO and wait for everything to
@@ -1184,7 +1198,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
}
if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, false);
return;
}
@@ -1195,7 +1209,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
mdname(mddev), b,
(unsigned long long)r10_bio->sector);
}
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, true);
return;
}
if (err_rdev)
@@ -1372,7 +1386,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
sectors = r10_bio->sectors;
if (!regular_request_wait(mddev, conf, bio, sectors)) {
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, false);
return;
}
@@ -2952,7 +2966,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
if (test_bit(R10BIO_WriteError,
&r10_bio->state))
close_write(r10_bio);
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, true);
}
}
}
@@ -2987,7 +3001,7 @@ static void raid10d(struct md_thread *thread)
if (test_bit(R10BIO_WriteError,
&r10_bio->state))
close_write(r10_bio);
- raid_end_bio_io(r10_bio);
+ raid_end_bio_io(r10_bio, true);
}
}
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v2 2/3] lib/raid6: Optimizing the raid6_select_algo time through asynchronous processing
From: kernel test robot @ 2026-02-07 7:22 UTC (permalink / raw)
To: sunliming, song, yukuai
Cc: oe-kbuild-all, linux-raid, linux-kernel, linan666, sunliming
In-Reply-To: <20260206054341.106878-3-sunliming@linux.dev>
Hi,
kernel test robot noticed the following build warnings:
[auto build test WARNING on akpm-mm/mm-nonmm-unstable]
[also build test WARNING on linus/master v6.19-rc8]
[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/sunliming-linux-dev/lib-raid6-Divide-the-raid6-algorithm-selection-process-into-two-parts/20260206-134850
base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-nonmm-unstable
patch link: https://lore.kernel.org/r/20260206054341.106878-3-sunliming%40linux.dev
patch subject: [PATCH v2 2/3] lib/raid6: Optimizing the raid6_select_algo time through asynchronous processing
config: i386-buildonly-randconfig-001-20260207 (https://download.01.org/0day-ci/archive/20260207/202602071500.ctQs6ZeY-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260207/202602071500.ctQs6ZeY-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/202602071500.ctQs6ZeY-lkp@intel.com/
All warnings (new ones prefixed by >>, old ones prefixed by <<):
>> WARNING: modpost: vmlinux: section mismatch in reference: raid6_exit+0x9 (section: .text) -> raid6_benchmark_work (section: .init.data)
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v2 2/3] lib/raid6: Optimizing the raid6_select_algo time through asynchronous processing
From: kernel test robot @ 2026-02-07 6:51 UTC (permalink / raw)
To: sunliming, song, yukuai
Cc: oe-kbuild-all, linux-raid, linux-kernel, linan666, sunliming
In-Reply-To: <20260206054341.106878-3-sunliming@linux.dev>
Hi,
kernel test robot noticed the following build warnings:
[auto build test WARNING on akpm-mm/mm-nonmm-unstable]
[also build test WARNING on linus/master v6.19-rc8]
[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/sunliming-linux-dev/lib-raid6-Divide-the-raid6-algorithm-selection-process-into-two-parts/20260206-134850
base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-nonmm-unstable
patch link: https://lore.kernel.org/r/20260206054341.106878-3-sunliming%40linux.dev
patch subject: [PATCH v2 2/3] lib/raid6: Optimizing the raid6_select_algo time through asynchronous processing
config: arc-randconfig-001-20260207 (https://download.01.org/0day-ci/archive/20260207/202602071412.HND36w5Q-lkp@intel.com/config)
compiler: arc-linux-gcc (GCC) 9.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260207/202602071412.HND36w5Q-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/202602071412.HND36w5Q-lkp@intel.com/
All warnings (new ones prefixed by >>, old ones prefixed by <<):
>> WARNING: modpost: lib/raid6/raid6_pq: section mismatch in reference: raid6_exit+0x2 (section: .text) -> raid6_benchmark_work (section: .init.data)
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v2 2/3] lib/raid6: Optimizing the raid6_select_algo time through asynchronous processing
From: kernel test robot @ 2026-02-06 19:34 UTC (permalink / raw)
To: sunliming, song, yukuai
Cc: llvm, oe-kbuild-all, linux-raid, linux-kernel, linan666,
sunliming
In-Reply-To: <20260206054341.106878-3-sunliming@linux.dev>
Hi,
kernel test robot noticed the following build warnings:
[auto build test WARNING on akpm-mm/mm-nonmm-unstable]
[also build test WARNING on linus/master v6.16-rc1 next-20260205]
[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/sunliming-linux-dev/lib-raid6-Divide-the-raid6-algorithm-selection-process-into-two-parts/20260206-134850
base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-nonmm-unstable
patch link: https://lore.kernel.org/r/20260206054341.106878-3-sunliming%40linux.dev
patch subject: [PATCH v2 2/3] lib/raid6: Optimizing the raid6_select_algo time through asynchronous processing
config: x86_64-kexec (https://download.01.org/0day-ci/archive/20260206/202602062049.sdwQ1NiZ-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260206/202602062049.sdwQ1NiZ-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/202602062049.sdwQ1NiZ-lkp@intel.com/
All warnings (new ones prefixed by >>, old ones prefixed by <<):
>> WARNING: modpost: lib/raid6/raid6_pq: section mismatch in reference: cleanup_module+0xc (section: .text) -> raid6_benchmark_work (section: .init.data)
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v2 2/3] lib/raid6: Optimizing the raid6_select_algo time through asynchronous processing
From: kernel test robot @ 2026-02-06 19:22 UTC (permalink / raw)
To: sunliming, song, yukuai
Cc: oe-kbuild-all, linux-raid, linux-kernel, linan666, sunliming
In-Reply-To: <20260206054341.106878-3-sunliming@linux.dev>
Hi,
kernel test robot noticed the following build warnings:
[auto build test WARNING on akpm-mm/mm-nonmm-unstable]
[also build test WARNING on linus/master v6.16-rc1 next-20260205]
[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/sunliming-linux-dev/lib-raid6-Divide-the-raid6-algorithm-selection-process-into-two-parts/20260206-134850
base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-nonmm-unstable
patch link: https://lore.kernel.org/r/20260206054341.106878-3-sunliming%40linux.dev
patch subject: [PATCH v2 2/3] lib/raid6: Optimizing the raid6_select_algo time through asynchronous processing
config: arm64-allnoconfig-bpf (https://download.01.org/0day-ci/archive/20260206/202602062027.j08UeCWD-lkp@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260206/202602062027.j08UeCWD-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/202602062027.j08UeCWD-lkp@intel.com/
All warnings (new ones prefixed by >>, old ones prefixed by <<):
>> WARNING: modpost: lib/raid6/raid6_pq: section mismatch in reference: raid6_exit+0xc (section: .text) -> raid6_benchmark_work (section: .init.data)
WARNING: modpost: lib/raid6/raid6_pq: section mismatch in reference: raid6_exit+0x10 (section: .text) -> raid6_benchmark_work (section: .init.data)
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v2 03/14] md/raid1: use folio for tmppage
From: Li Nan @ 2026-02-06 9:07 UTC (permalink / raw)
To: yukuai, Li Nan, song; +Cc: xni, linux-raid, linux-kernel, yangerkun, yi.zhang
In-Reply-To: <44521568-3ac0-4374-9c3b-756b8e18192f@fnnas.com>
在 2026/2/5 15:33, Yu Kuai 写道:
> Hi,
>
> 在 2026/2/5 15:23, Li Nan 写道:
>> Yeah, should we introduce safe_put_folio()? Or just check NULL here.
>
> Yes, and don't copy implementation. Just convert safe_put_page(page) to
> safe_put_folio(page_folio(page)) first.
>
page cannot be NULL in page_folio(), and the code would be:
if (page)
safe_put_folio(page_folio(page))
This also looks odd. Keeping both functions and removing the page one
after the last reference to it in RAID5 is removed seems better. What do
you think?
--
Thanks,
Nan
^ permalink raw reply
* [PATCH v2 3/3] lib/raid6: Delete the RAID6_PQ_BENCHMARK config
From: sunliming @ 2026-02-06 5:43 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, linan666, sunliming
In-Reply-To: <20260206054341.106878-1-sunliming@linux.dev>
From: sunliming <sunliming@kylinos.cn>
Now RAID6 PQ functions is automatically choosed and the
RAID6_PQ_BENCHMARK is not needed.
Signed-off-by: sunliming <sunliming@kylinos.cn>
---
include/linux/raid/pq.h | 3 ---
lib/Kconfig | 8 --------
2 files changed, 11 deletions(-)
diff --git a/include/linux/raid/pq.h b/include/linux/raid/pq.h
index 2467b3be15c9..6378ec4ae4ba 100644
--- a/include/linux/raid/pq.h
+++ b/include/linux/raid/pq.h
@@ -67,9 +67,6 @@ extern const char raid6_empty_zero_page[PAGE_SIZE];
#define MODULE_DESCRIPTION(desc)
#define subsys_initcall(x)
#define module_exit(x)
-
-#define IS_ENABLED(x) (x)
-#define CONFIG_RAID6_PQ_BENCHMARK 1
#endif /* __KERNEL__ */
/* Routine choices */
diff --git a/lib/Kconfig b/lib/Kconfig
index 2923924bea78..841a0245a2c4 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -11,14 +11,6 @@ menu "Library routines"
config RAID6_PQ
tristate
-config RAID6_PQ_BENCHMARK
- bool "Automatically choose fastest RAID6 PQ functions"
- depends on RAID6_PQ
- default y
- help
- Benchmark all available RAID6 PQ functions on init and choose the
- fastest one.
-
config LINEAR_RANGES
tristate
--
2.25.1
^ permalink raw reply related
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