All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Yu Kuai" <yukuai@kernel.org>
Cc: linux-raid@vger.kernel.org, yukuai@fygo.io
Subject: Re: [PATCH v3 07/21] md/md-llbitmap: grow the page cache in place for reshape
Date: Tue, 28 Jul 2026 09:09:45 +0000	[thread overview]
Message-ID: <20260728090946.0A7951F000E9@smtp.kernel.org> (raw)
In-Reply-To: <7f146fb22b6051aea3b0e79072d4403526ed46f0.1785206690.git.yukuai@fygo.io>

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:

New issues:
- [High] Use-After-Free on `llbitmap->pctl` array during bitmap resize.
- [High] Block IO recursion deadlock due to `GFP_KERNEL` allocation under `reconfig_mutex`.
- [High] Out-Of-Bounds array access during resize due to stale `chunkshift`.

Pre-existing issues:
- [High] Divide-by-zero crash in `llbitmap_calculate_chunks` on 32-bit systems due to `chunksize` overflow.
- [High] Use-After-Free timer race during `llbitmap_destroy`.
- [High] Out-of-Bounds disk write due to missing `BITMAP_DATA_OFFSET` in calculation.
--

--- Patch [7]: [PATCH v3 07/21] md/md-llbitmap: grow the page cache in place for reshape ---
commit 7e002f8cabd473784285f63600d75c1d7d7d30c4
Author: Yu Kuai <yukuai@fygo.io>

md/md-llbitmap: grow the page cache in place for reshape

This patch uses the page-control helpers to grow the llbitmap's cached pages
in place for resize and later reshape preparation, instead of rebuilding the
whole cache.

> diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
> index 4c3fc4b35aff0..1ab9b1689fd80 100644
> --- a/drivers/md/md-llbitmap.c
> +++ b/drivers/md/md-llbitmap.c
> @@ -416,6 +416,19 @@ static char state_machine[BitStateCount][BitmapActionCount] = {
>  };
>  
>  static void __llbitmap_flush(struct mddev *mddev);
> +static void llbitmap_flush(struct mddev *mddev);
> +static void llbitmap_update_sb(void *data);
> +
> +static void llbitmap_calculate_chunks(struct mddev *mddev, sector_t blocks,
> +				      unsigned long *chunksize,
> +				      unsigned long *chunks)
> +{
> +	*chunks = DIV_ROUND_UP_SECTOR_T(blocks, *chunksize);
> +	while (*chunks > mddev->bitmap_info.space << SECTOR_SHIFT) {

[Severity: High]
This is a pre-existing issue, but does this calculation allow the on-disk
footprint to exceed the reserved space limit?

The check ensures *chunks does not exceed mddev->bitmap_info.space, but
the on-disk layout includes an additional 1024 bytes (BITMAP_DATA_OFFSET)
for the superblock before the raw bitmap state data.

When llbitmap_write_page() writes the tail chunks to disk, could it write
1024 bytes past the reserved bitmap region and corrupt adjacent data?

[Severity: High]
This is a pre-existing issue, but does this loop risk a divide by zero on
32-bit systems?

If *chunksize is 32 bits, and the array is extremely large with very small
reserved space, *chunksize could shift until it overflows to 0.

Would the subsequent call to DIV_ROUND_UP_SECTOR_T(blocks, 0) cause a crash
when the sysfs size is written?

> +		*chunksize = *chunksize << 1;
> +		*chunks = DIV_ROUND_UP_SECTOR_T(blocks, *chunksize);
> +	}
> +}

[ ... ]

> @@ -655,6 +668,48 @@ static unsigned int llbitmap_reserved_pages(struct llbitmap *llbitmap)
>  			    PAGE_SIZE);
>  }
>  
> +static int llbitmap_expand_pages(struct llbitmap *llbitmap,
> +				 unsigned long chunks)
> +{
> +	struct llbitmap_page_ctl **pctl;
> +	unsigned int old_nr_pages = llbitmap->nr_pages;
> +	unsigned int nr_pages = llbitmap_used_pages(llbitmap, chunks);
> +	unsigned int i;
> +	int ret;
> +
> +	if (nr_pages <= old_nr_pages)
> +		return 0;
> +
> +	pctl = kcalloc(nr_pages, sizeof(*pctl), GFP_KERNEL);

[Severity: High]
Can this allocation trigger a block IO recursion deadlock?

This is reached via array_size_store() which acquires mddev_lock()
(taking reconfig_mutex) without setting memalloc_noio_save() context.

Under memory pressure, GFP_KERNEL can enter direct reclaim and issue I/O
writeback to the MD array. If the array superblock needs updating,
md_write_start() waits on mddev->sb_wait for MD_SB_CHANGE_PENDING to clear.

Since the management thread must clear this flag but blocks trying to acquire
reconfig_mutex held by this resizing thread, does this result in a deadlock?

> +	if (!pctl)
> +		return -ENOMEM;
> +
> +	if (llbitmap->pctl)
> +		memcpy(pctl, llbitmap->pctl,
> +		       array_size(old_nr_pages, sizeof(*pctl)));
> +
> +	for (i = old_nr_pages; i < nr_pages; i++) {
> +		pctl[i] = llbitmap_alloc_page_ctl(llbitmap, i);
> +		if (IS_ERR(pctl[i]))
> +			goto err_alloc_ptr;
> +	}
> +
> +	kfree(llbitmap->pctl);
> +	llbitmap->pctl = pctl;

[Severity: High]
Could this cause a use-after-free if concurrent IO is happening?

The MD array does not suspend IO for sysfs-triggered resize operations.
The concurrent IO path accesses this array in llbitmap_start_write():

llbitmap_start_write()
    llbitmap_raise_barrier(llbitmap, page_start);

This happens without holding mddev->bitmap_info.mutex and without RCU
protection. If the IO path dereferences the array just after this kfree()
completes, will it trigger a panic?

> +	llbitmap->nr_pages = nr_pages;
> +	return 0;
> +

[ ... ]

> @@ -1171,24 +1254,53 @@ static int llbitmap_create(struct mddev *mddev)
>  static int llbitmap_resize(struct mddev *mddev, sector_t blocks, int chunksize)
>  {

[ ... ]

> +	if (reshape) {
> +		llbitmap->chunks = max(old_chunks, chunks);
> +	} else {

[Severity: High]
Does this cause an out-of-bounds array access during a reshape?

During reshape, this path updates llbitmap->chunks to a potentially larger
capacity but does not update llbitmap->chunkshift.

The active IO path continues to map array offsets to bitmap chunk indices
using the smaller old chunkshift:

llbitmap_start_write()
    start = offset >> llbitmap->chunkshift;
    ...
    page_start = (start + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;

Because the old chunkshift maps to a larger number of total chunks than the
new chunks capacity (which was reduced by doubling bitmap_chunksize), could
an IO towards the end of the new array compute a page_start index that
exceeds the capacity of the newly reallocated llbitmap->pctl array?

> +		if (blocks < old_blocks && chunks < old_chunks)
> +			llbitmap_mark_range(llbitmap, chunks, old_chunks - 1,
> +					    BitUnwritten);
> +		mddev->bitmap_info.chunksize = bitmap_chunksize;
> +		llbitmap->chunks = chunks;
> +		llbitmap->sync_size = blocks;
> +		llbitmap_update_sb(llbitmap);
> +	}
> +	__llbitmap_flush(mddev);
> +	mutex_unlock(&mddev->bitmap_info.mutex);
>  	return 0;

[Severity: High]
This is a pre-existing issue, but is there a use-after-free race between
llbitmap_destroy() and the daemon work queue?

llbitmap_destroy() deletes the timer and then flushes the workqueue:

llbitmap_destroy()
    timer_delete_sync(&llbitmap->pending_timer);
    flush_workqueue(md_llbitmap_io_wq);

If md_llbitmap_daemon_fn() is actively executing in the workqueue while
teardown happens, the timer is not pending, so timer_delete_sync() returns
immediately.

The running daemon work then evaluates restart = true and re-arms the timer:

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

Could flush_workqueue() complete, allowing llbitmap_destroy() to free the
llbitmap structure, while the re-armed timer later fires and accesses the
freed memory?

> +
> +out:
> +	mutex_unlock(&mddev->bitmap_info.mutex);
> +	return ret;
>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1785206690.git.yukuai@fygo.io?part=7

  reply	other threads:[~2026-07-28  9:09 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-28  8:49 [PATCH v3 00/21] md/md-llbitmap: support reshape for RAID10 and RAID5 Yu Kuai
2026-07-28  8:49 ` [PATCH v3 01/21] md/raid5: round bitmap stripes with sector division Yu Kuai
2026-07-28  9:03   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 02/21] md: add exact bitmap mapping and reshape hooks Yu Kuai
2026-07-28  8:49 ` [PATCH v3 03/21] md: skip bitmap accounting for empty write ranges Yu Kuai
2026-07-28  8:49 ` [PATCH v3 04/21] md: add helper to split bios at reshape offset Yu Kuai
2026-07-28  9:03   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 05/21] md/md-llbitmap: track bitmap sync_size explicitly Yu Kuai
2026-07-28  9:16   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 06/21] md/md-llbitmap: allocate page controls independently Yu Kuai
2026-07-28  9:06   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 07/21] md/md-llbitmap: grow the page cache in place for reshape Yu Kuai
2026-07-28  9:09   ` sashiko-bot [this message]
2026-07-28  8:49 ` [PATCH v3 08/21] md/md-llbitmap: track target reshape geometry fields Yu Kuai
2026-07-28  9:12   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 09/21] md/md-llbitmap: finish reshape geometry Yu Kuai
2026-07-28  9:14   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 10/21] md/md-llbitmap: refuse reshape while llbitmap still needs sync Yu Kuai
2026-07-28  9:12   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 11/21] md/md-llbitmap: add reshape range mapping helpers Yu Kuai
2026-07-28  9:11   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 12/21] md/md-llbitmap: don't skip reshape ranges from bitmap state Yu Kuai
2026-07-28  8:49 ` [PATCH v3 13/21] md/md-llbitmap: remap checkpointed bits as reshape progresses Yu Kuai
2026-07-28  9:06   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 14/21] md/md-llbitmap: clamp state-machine walks to tracked bits Yu Kuai
2026-07-28  9:13   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 15/21] md/raid10: reject llbitmap reshape when md chunk shrinks Yu Kuai
2026-07-28  9:15   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 16/21] md/raid10: wire llbitmap reshape lifecycle Yu Kuai
2026-07-28  9:22   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 17/21] md/raid10: split reshape bios before bitmap accounting Yu Kuai
2026-07-28  9:15   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 18/21] md/raid5: add exact old and new llbitmap mapping helpers Yu Kuai
2026-07-28  9:25   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 19/21] md/raid5: reject llbitmap reshape when md chunk shrinks Yu Kuai
2026-07-28  9:22   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 20/21] md/raid5: wire llbitmap reshape lifecycle Yu Kuai
2026-07-28  9:21   ` sashiko-bot
2026-07-28  8:49 ` [PATCH v3 21/21] md/raid5: split reshape bios before bitmap accounting Yu Kuai
2026-07-28  9:26   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260728090946.0A7951F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-raid@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=yukuai@fygo.io \
    --cc=yukuai@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.