Re: [PATCH v5 20/29] md/md-llbitmap: don't skip reshape ranges from bitmap state

[email protected] Sun, 02 Aug 2026 20:31:01 +0000
Newsgroups gmane.linux.raid
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(=
s) to consider:

Pre-existing issues:
- [Critical] This problem wasn't introduced by this patch, but a lockless r=
ace condition in `llbitmap_set_page_dirty` causes dirty bitmap blocks to be=
 lost in memory and never flushed to disk.
- [High] This problem wasn't introduced by this patch, but integer truncati=
on of `blocks` can cause an infinite loop in the `md_do_sync` thread.
--

--- Patch [20]: [PATCH v5 20/29] md/md-llbitmap: don't skip reshape ranges =
from bitmap state ---
commit c6db76f6bc970107f68d37fc602584cc2c0e0a1b
Author: Yu Kuai <[email protected]>

md/md-llbitmap: don't skip reshape ranges from bitmap state

This commit modifies md-llbitmap to stop using stale bitmap state for
skipping reshape ranges. It ensures that reshape progress is tracked purely
by array metadata. This prevents data loss after a restart before checkpoin=
ts
are persisted to disk.

Tested-by: Mykola Marzhan <[email protected]>

> diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
> index fa16a4224c45a..a20e55fdf82b0 100644
> --- a/drivers/md/md-llbitmap.c
> +++ b/drivers/md/md-llbitmap.c
> @@ -1707,6 +1707,14 @@ static sector_t llbitmap_skip_sync_blocks(struct m=
ddev *mddev, sector_t offset)

[Severity: High]
This isn't a bug introduced by this patch, but can integer truncation of
blocks cause an infinite loop in the md_do_sync() thread?

In llbitmap_skip_sync_blocks(), blocks is declared as an int:

    int blocks =3D llbitmap->chunksize - (offset & (llbitmap->chunksize - 1=
));

If the array size and bitmap space require chunksize to exceed INT_MAX (e.g=
.,
a >8TB array with a small bitmap space), chunksize will be >=3D 2^31. Can t=
he
subtraction yield a value >=3D 2^31, which truncates into a negative 32-bit=
 int
(e.g., -1024)?

When this negative int is returned as a 64-bit sector_t, does it sign-extend
to a massive positive value? If md_do_sync() adds this value to the current
sync sector index, could it cause the index to overflow and decrease, loopi=
ng
endlessly back and forth?

>  		return 0;
>  	c =3D llbitmap_read(llbitmap, p);
> =20
> +	/*
> +	 * Reshape progress is tracked by array metadata rather than llbitmap.
> +	 * Skipping reshape ranges from stale bitmap state can lose data after a
> +	 * restart before the corresponding bits are checkpointed to disk.
> +	 */
> +	if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
> +		return 0;
> +
>  	/* always skip unwritten blocks */
>  	if (c =3D=3D BitUnwritten)
>  		return blocks;

[Severity: Critical]
This is a pre-existing issue, but a lockless race condition in
llbitmap_set_page_dirty() can cause dirty bitmap blocks to be lost in memory
and never flushed to disk.

Can this sequence actually occur? If llbitmap_set_page_dirty() is called
concurrently with the llbitmap_unplug_fn() flusher thread, the writer sets
the LLPageDirty flag before setting the specific block bit:

drivers/md/md-llbitmap.c:llbitmap_set_page_dirty() {
    ...
    if (!test_bit(LLPageDirty, &pctl->flags))
        set_bit(LLPageDirty, &pctl->flags);
   =20
    // race window here
   =20
    set_bit(block, pctl->dirty);
    ...
}

If the flusher thread clears LLPageDirty and checks pctl->dirty between the=
se
two operations:

drivers/md/md-llbitmap.c:llbitmap_unplug_fn() {
    ...
    if (!test_bit(LLPageDirty, &llbitmap->pctl[i]->flags) ||
        !test_and_clear_bit(LLPageDirty, &llbitmap->pctl[i]->flags))
        continue;
    ...
}

Will it miss the dirty block? The writer then sets the block bit, but
because LLPageDirty is now 0, the flusher will ignore this page indefinitely
until another block happens to be dirtied.

If a dirty block is not flushed to the disk bitmap, will the array fail to
resync that block after a crash or unclean shutdown, leaving stale data on
one of the drives?

--=20
Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260802195038.1642=
[email protected]?part=3D20