Move the barrier raise operation before calling llbitmap_state_machine()
in both llbitmap_start_write() and llbitmap_start_discard(). This
ensures the barrier is in place before any state transitions occur,
preventing potential race conditions where the state machine could
complete before the barrier is properly raised.
Cc: stable@vger.kernel.org
Fixes: 5ab829f1971d ("md/md-llbitmap: introduce new lockless bitmap")
Signed-off-by: Yu Kuai <yukuai@fnnas.com>
---
drivers/md/md-llbitmap.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
index 30d7e36b22c4..5f9e7004e3e3 100644
--- a/drivers/md/md-llbitmap.c
+++ b/drivers/md/md-llbitmap.c
@@ -1070,12 +1070,12 @@ static void llbitmap_start_write(struct mddev *mddev, sector_t offset,
int page_start = (start + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
int page_end = (end + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
- llbitmap_state_machine(llbitmap, start, end, BitmapActionStartwrite);
-
while (page_start <= page_end) {
llbitmap_raise_barrier(llbitmap, page_start);
page_start++;
}
+
+ llbitmap_state_machine(llbitmap, start, end, BitmapActionStartwrite);
}
static void llbitmap_end_write(struct mddev *mddev, sector_t offset,
@@ -1102,12 +1102,12 @@ static void llbitmap_start_discard(struct mddev *mddev, sector_t offset,
int page_start = (start + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
int page_end = (end + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
- llbitmap_state_machine(llbitmap, start, end, BitmapActionDiscard);
-
while (page_start <= page_end) {
llbitmap_raise_barrier(llbitmap, page_start);
page_start++;
}
+
+ llbitmap_state_machine(llbitmap, start, end, BitmapActionDiscard);
}
static void llbitmap_end_discard(struct mddev *mddev, sector_t offset,
--
2.51.0
On Mon, Feb 23, 2026 at 10:42 AM Yu Kuai <yukuai@fnnas.com> wrote:
>
> Move the barrier raise operation before calling llbitmap_state_machine()
> in both llbitmap_start_write() and llbitmap_start_discard(). This
> ensures the barrier is in place before any state transitions occur,
> preventing potential race conditions where the state machine could
> complete before the barrier is properly raised.
Hi Kuai
In the above commit message, race conditions are mentioned. I want to
give an example here to check if I understand correctly.
raid1 with 2 disks is used in this case.
T0: Thread A calls llbitmap_state_machine() and state of bit is set to BitDirty
T1: Thread daemon calls llbitmap_daemon_work() and the state of the
bit is set to BitClean from BitDirty.
(Now the state is already wrong)
T2: Thread A calls llbitmap_raise_barrier to wait Thread daemon
finishes and go on working
T3: data is written to disk1 and disk2. A power failure occurs.
(The data on disk1 and disk2 maybe different, so a data curruption happens)
Does this case belong the race conditions you mentioned in the commit
message? Can you add one race condtion in your message?
Best Regards
Xiao
>
> Cc: stable@vger.kernel.org
> Fixes: 5ab829f1971d ("md/md-llbitmap: introduce new lockless bitmap")
> Signed-off-by: Yu Kuai <yukuai@fnnas.com>
> ---
> drivers/md/md-llbitmap.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
> index 30d7e36b22c4..5f9e7004e3e3 100644
> --- a/drivers/md/md-llbitmap.c
> +++ b/drivers/md/md-llbitmap.c
> @@ -1070,12 +1070,12 @@ static void llbitmap_start_write(struct mddev *mddev, sector_t offset,
> int page_start = (start + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
> int page_end = (end + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
>
> - llbitmap_state_machine(llbitmap, start, end, BitmapActionStartwrite);
> -
> while (page_start <= page_end) {
> llbitmap_raise_barrier(llbitmap, page_start);
> page_start++;
> }
> +
> + llbitmap_state_machine(llbitmap, start, end, BitmapActionStartwrite);
> }
>
> static void llbitmap_end_write(struct mddev *mddev, sector_t offset,
> @@ -1102,12 +1102,12 @@ static void llbitmap_start_discard(struct mddev *mddev, sector_t offset,
> int page_start = (start + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
> int page_end = (end + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
>
> - llbitmap_state_machine(llbitmap, start, end, BitmapActionDiscard);
> -
> while (page_start <= page_end) {
> llbitmap_raise_barrier(llbitmap, page_start);
> page_start++;
> }
> +
> + llbitmap_state_machine(llbitmap, start, end, BitmapActionDiscard);
> }
>
> static void llbitmap_end_discard(struct mddev *mddev, sector_t offset,
> --
> 2.51.0
>
>
Hi,
在 2026/3/9 21:05, Xiao Ni 写道:
> On Mon, Feb 23, 2026 at 10:42 AM Yu Kuai <yukuai@fnnas.com> wrote:
>> Move the barrier raise operation before calling llbitmap_state_machine()
>> in both llbitmap_start_write() and llbitmap_start_discard(). This
>> ensures the barrier is in place before any state transitions occur,
>> preventing potential race conditions where the state machine could
>> complete before the barrier is properly raised.
> Hi Kuai
>
> In the above commit message, race conditions are mentioned. I want to
> give an example here to check if I understand correctly.
>
> raid1 with 2 disks is used in this case.
> T0: Thread A calls llbitmap_state_machine() and state of bit is set to BitDirty
> T1: Thread daemon calls llbitmap_daemon_work() and the state of the
> bit is set to BitClean from BitDirty.
> (Now the state is already wrong)
> T2: Thread A calls llbitmap_raise_barrier to wait Thread daemon
> finishes and go on working
> T3: data is written to disk1 and disk2. A power failure occurs.
> (The data on disk1 and disk2 maybe different, so a data curruption happens)
>
> Does this case belong the race conditions you mentioned in the commit
> message? Can you add one race condtion in your message?
This is not that complex, the reason state machine from fast path can concurrent
with each other is that they both change state to the same state, and obliviously
they can't concurrent from slow path, this is why the barrier is needed. And I
made this mistake in the first version.
>
> Best Regards
> Xiao
>
>> Cc: stable@vger.kernel.org
>> Fixes: 5ab829f1971d ("md/md-llbitmap: introduce new lockless bitmap")
>> Signed-off-by: Yu Kuai <yukuai@fnnas.com>
>> ---
>> drivers/md/md-llbitmap.c | 8 ++++----
>> 1 file changed, 4 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
>> index 30d7e36b22c4..5f9e7004e3e3 100644
>> --- a/drivers/md/md-llbitmap.c
>> +++ b/drivers/md/md-llbitmap.c
>> @@ -1070,12 +1070,12 @@ static void llbitmap_start_write(struct mddev *mddev, sector_t offset,
>> int page_start = (start + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
>> int page_end = (end + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
>>
>> - llbitmap_state_machine(llbitmap, start, end, BitmapActionStartwrite);
>> -
>> while (page_start <= page_end) {
>> llbitmap_raise_barrier(llbitmap, page_start);
>> page_start++;
>> }
>> +
>> + llbitmap_state_machine(llbitmap, start, end, BitmapActionStartwrite);
>> }
>>
>> static void llbitmap_end_write(struct mddev *mddev, sector_t offset,
>> @@ -1102,12 +1102,12 @@ static void llbitmap_start_discard(struct mddev *mddev, sector_t offset,
>> int page_start = (start + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
>> int page_end = (end + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
>>
>> - llbitmap_state_machine(llbitmap, start, end, BitmapActionDiscard);
>> -
>> while (page_start <= page_end) {
>> llbitmap_raise_barrier(llbitmap, page_start);
>> page_start++;
>> }
>> +
>> + llbitmap_state_machine(llbitmap, start, end, BitmapActionDiscard);
>> }
>>
>> static void llbitmap_end_discard(struct mddev *mddev, sector_t offset,
>> --
>> 2.51.0
>>
>>
--
Thansk,
Kuai
© 2016 - 2026 Red Hat, Inc.