[PATCH] md/raid5: reject a per-device size smaller than one chunk
From: Zizhi Wo
Date: Wed Sep 16 2026 - 06:04:34 EST
From: Zizhi Wo <wozizhi@xxxxxxxxxx>
Both raid5_run() and raid5_resize() align the per-device size down to a
whole multiple of the chunk size:
mddev->dev_sectors &= ~(chunk_sectors - 1);
Neither checks the result, so a size smaller than one chunk silently
becomes zero.
In raid5_run() that is harmless: the array size is derived from the same
zero, so the disk just ends up with no capacity.
In raid5_resize() it leaves the array inconsistent -- mddev->dev_sectors
becomes zero, while mddev->array_sectors and the gendisk capacity keep the
previous. A later raid4/raid5 -> raid0 takeover copies the zero into every
rdev->sectors (raid0_takeover_raid45()), so create_strip_zones() builds a
strip zone table whose zone_end is zero. Any read then passes
bio_check_eod() against the stale capacity and hits the BUG() in
find_zone():
kernel BUG at drivers/md/raid0.c:318!
Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
CPU: 45 UID: 0 PID: 1300 Comm: mdadm Not tainted 7.3.0-rc3+ #106 PREEMPT(full)
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-4.fc41 04/01/2014
RIP: 0010:raid0_make_request+0x10cb/0x16a0
Call Trace:
<TASK>
md_handle_request+0x566/0xb40
__submit_bio+0x2b2/0x600
submit_bio_noacct_nocheck+0x509/0xb30
block_read_full_folio+0x364/0x6d0
filemap_read_folio+0xa2/0x200
do_read_cache_folio+0x1b6/0x330
read_part_sector+0xb6/0x2a0
read_lba+0x17d/0x280
efi_partition+0x2a6/0x2520
bdev_disk_changed+0x6e0/0xfa0
......
bdev_open+0x214/0xc40
Reject a size smaller than one chunk in both functions, so that a running
raid4/raid5 array always has mddev->dev_sectors >= one chunk.
The check is done where the value takes effect, not where it is assigned.
mddev->dev_sectors is written from several places, and none of them can
tell whether the value is usable: the chunk size may still change later.
raid5_run() and raid5_resize() are where every input is final, so one check
in each covers them all.
Fixes: eea136d69f9f ("md: fix buglet in RAID5 -> RAID0 conversion.")
Signed-off-by: Zizhi Wo <wozizhi@xxxxxxxxxx>
---
drivers/md/raid5.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index b91545ce090d..e0f1a8e7bd3a 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -8201,10 +8201,16 @@ static int raid5_run(struct mddev *mddev)
goto abort;
}
/* device size must be a multiple of chunk size */
mddev->dev_sectors &= ~((sector_t)mddev->chunk_sectors - 1);
+ if (!mddev->dev_sectors) {
+ pr_warn("md/raid:%s: device size is smaller than one chunk\n",
+ mdname(mddev));
+ ret = -EINVAL;
+ goto abort;
+ }
mddev->resync_max_sectors = mddev->dev_sectors;
if (mddev->degraded > dirty_parity_disks &&
mddev->resync_offset != MaxSector) {
if (test_bit(MD_HAS_PPL, &mddev->flags))
@@ -8534,10 +8540,12 @@ static int raid5_resize(struct mddev *mddev, sector_t sectors)
struct r5conf *conf = mddev->private;
if (raid5_has_log(conf) || raid5_has_ppl(conf))
return -EINVAL;
sectors &= ~((sector_t)conf->chunk_sectors - 1);
+ if (!sectors)
+ return -EINVAL;
newsize = raid5_size(mddev, sectors, mddev->raid_disks);
if (mddev->external_size &&
mddev->array_sectors > newsize)
return -EINVAL;
--
2.52.0