Re: [PATCH v4 15/25] md/md-llbitmap: add reshape range mapping helpers

[email protected] Sat, 01 Aug 2026 17:47:55 +0000
Newsgroups org.kernel.vger.linux-raid
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 4 potential issue(=
s) to consider:

New issues:
- [High] Missing post-mapping clamp in llbitmap_map_layout causes out-of-bo=
unds array access.
- [High] Missing RAID5 personality callbacks for exact bitmap mapping cause=
 array-sector I/Os to be improperly clamped and silently dropped.
- [High] Bios are not split at the reshape boundary before bitmap processin=
g, causing I/Os to span the boundary and corrupt sync state.

Pre-existing issues:
- [High] Timer teardown race in llbitmap_destroy allows the daemon workqueu=
e to re-arm the timer on a freed structure.
--

--- Patch [15]: [PATCH v4 15/25] md/md-llbitmap: add reshape range mapping =
helpers ---
commit 9c9574c9c91f5e10866a7c4d06542de767878cc2
Author: Yu Kuai <[email protected]>
Subject: md/md-llbitmap: add reshape range mapping helpers

This patch updates llbitmap to choose between old and new geometry during a
reshape and to encode exact bitmap ranges. It also distinguishes writes from
discards for range preparation and clamps pre-map ranges to array-sector
limits.

Link: https://lore.kernel.org/all/20260726185916.2223460-1-mykola@meshstor.=
io/

> diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
> --- a/drivers/md/md-llbitmap.c
> +++ b/drivers/md/md-llbitmap.c
[ ... ]
> +static sector_t llbitmap_logical_size(struct llbitmap *llbitmap, bool pr=
evious)
> +{
> +	struct mddev *mddev =3D llbitmap->mddev;
> +
> +	if (!mddev->private || !mddev->pers ||
> +	    !mddev->pers->bitmap_array_sectors)
> +		return llbitmap_personality_sync_size(llbitmap, previous);
> +	return mddev->pers->bitmap_array_sectors(mddev, previous);
> +}

[Severity: High]
Does this fallback to llbitmap_personality_sync_size() hide the fact that
the raid5 personality doesn't implement bitmap_array_sectors or
bitmap_sector_map?

If an I/O is issued beyond the component size (for instance, past 1/N of
the array size), won't the pre-map clamp in llbitmap_map_layout() see
start >=3D limit and force sectors =3D 0?=20

This would silently drop the bitmap update, leading to permanent data
corruption if the system crashes and fails to resync those unrecorded
regions.

[ ... ]
> +static void llbitmap_map_layout(struct llbitmap *llbitmap, sector_t *off=
set,
> +				unsigned long *sectors, bool previous)
> +{
[ ... ]
> +	if (llbitmap->mddev->pers->bitmap_sector_map)
> +		llbitmap->mddev->pers->bitmap_sector_map(llbitmap->mddev, offset,
> +							 sectors, previous);
> +	else if (!previous && llbitmap->mddev->pers->bitmap_sector)
> +		llbitmap->mddev->pers->bitmap_sector(llbitmap->mddev, offset,
> +							 sectors);
> +}

[Severity: High]
Is there a missing post-mapping clamp against the component sync_size here?

When a write near the end of the array is passed to llbitmap_start_write(),
the pre-map clamp correctly limits offset and sectors to the array size.
However, bitmap_sector() translates only the offset to component space
without scaling down the sectors value.

If offset + sectors exceeds the component size, couldn't this cause the
calculated page_end index in llbitmap_start_write() to exceed
llbitmap->nr_pages? This would result in an out-of-bounds read beyond the
llbitmap->pctl pointer array and memory corruption when accessing the active
percpu_ref.

[ ... ]
> @@ -1394,11 +1475,35 @@ static void llbitmap_destroy(struct mddev *mddev)
[ ... ]
>  	mutex_unlock(&mddev->bitmap_info.mutex);
>  }

[Severity: High]
This is a pre-existing issue, but does this teardown sequence have a
use-after-free race with the daemon workqueue?

If the timer fires right before timer_delete_sync(), it queues daemon_work.
flush_workqueue() then blocks until md_llbitmap_daemon_fn() finishes.
However, md_llbitmap_daemon_fn() can unconditionally re-arm the timer:

	if (restart)
		mod_timer(&llbitmap->pending_timer, ...);

If the timer is re-armed during the flush, won't it fire again after
kfree(llbitmap) executes, dereferencing the freed structure?

> +static bool llbitmap_map_previous(struct llbitmap *llbitmap, sector_t of=
fset,
> +				  unsigned long sectors)
> +{
> +	struct mddev *mddev =3D llbitmap->mddev;
> +	sector_t boundary =3D READ_ONCE(mddev->reshape_position);
> +
> +	if (boundary =3D=3D MaxSector)
> +		return false;
> +
> +	WARN_ON_ONCE(sectors && offset < boundary && offset + sectors > boundar=
y);

[Severity: High]
Can bios span across the reshape boundary and trigger this warning?

It appears mddev_bio_split_at_reshape_offset() is exported in md.c but is
never called before md_account_bio(). Because the bio isn't split,
md_bitmap_start() will receive the original, un-split bio from the block
layer.

If a spanning bio triggers this warning, llbitmap_map_previous() forces the
entire bio to be mapped to a single geometry. Won't this fail to mark the
necessary bits in the other geometry and corrupt the sync state?

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