[packages/kernel/LINUX_6_18] More checks and more upstream compatibility
arekm
arekm at pld-linux.org
Mon Aug 24 11:53:42 CEST 2026
commit e8f83729bef9bc7c5233c819c868b9207b330cc2
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date: Mon Aug 24 11:16:55 2026 +0200
More checks and more upstream compatibility
kernel-md-hotadd-lbs-guard.patch | 40 +++++++--
kernel-md-lbs-forward-compat.patch | 163 ++++++++++++++++++++++++++++---------
2 files changed, 159 insertions(+), 44 deletions(-)
---
diff --git a/kernel-md-hotadd-lbs-guard.patch b/kernel-md-hotadd-lbs-guard.patch
index 0af69f44..4cccf273 100644
--- a/kernel-md-hotadd-lbs-guard.patch
+++ b/kernel-md-hotadd-lbs-guard.patch
@@ -1,7 +1,8 @@
Subject: md: prevent adding disks with larger logical_block_size to active arrays
Upstream 6c6b66f65e55 ("md: prevent adding disks with larger
-logical_block_size to active arrays"), verbatim.
+logical_block_size to active arrays"), plus the same check for the
+raid1 replacement path.
mddev_stack_new_rdev() stacks the new member's queue limits into the
array's, and blk_stack_limits() takes the maximum logical block size.
@@ -14,14 +15,31 @@ block size of the live array, which makes its partition table unreadable:
partprobe /dev/md0 # md0p1 is gone
The bug predates 2.6.12 and is reachable for every array that assembles
-here. kernel-md-lbs-forward-compat.patch widens that set to arrays
-created under >= 6.19, so carry the upstream fix next to it.
+here. Fixed upstream in 6.19; 6.18.y has not picked it up.
-Fixed upstream in 6.19; 6.18.y has not picked it up.
+Local extension on top of the upstream hunk: the raid1_add_disk()
+replacement branch never goes through mddev_stack_new_rdev(), dodging
+both the guard and limits stacking, so route it through - exactly as
+the raid10 replacement branch already does. This hole exists upstream
+too.
+Scope matches upstream: the guard covers the md core hot-add path
+(raid1/raid10, now including the raid1 replacement). linear_add()
+restacks limits without it and raid456 does not restack on hot-add, so
+neither is covered - same as upstream.
+
+Accepted behaviour change: a 4Kn spare or replacement can no longer be
+hot-added to a running 512-byte array - previously this succeeded while
+silently growing the array's logical block size. That includes a legacy
+mixed 512+4Kn array assembled degraded from its 512-byte members only:
+its queue is 512 bytes and the original 4Kn member cannot be re-added.
+This kernel has no interface to prepare the array for such a member;
+when that trade-off is wanted, boot a >= 6.19 kernel, write the new
+size to md/logical_block_size and add the disk there.
+---
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
-@@ -6144,6 +6144,13 @@
+@@ -6141,6 +6141,13 @@
if (mddev_is_dm(mddev))
return 0;
@@ -35,3 +53,15 @@ Fixed upstream in 6.19; 6.18.y has not picked it up.
lim = queue_limits_start_update(mddev->gendisk->queue);
queue_limits_stack_bdev(&lim, rdev->bdev, rdev->data_offset,
mddev->gendisk->disk_name);
+--- a/drivers/md/raid1.c
++++ b/drivers/md/raid1.c
+@@ -1974,6 +1974,9 @@
+
+ if (err && repl_slot >= 0) {
+ /* Add this device as a replacement */
++ err = mddev_stack_new_rdev(mddev, rdev);
++ if (err)
++ return err;
+ clear_bit(In_sync, &rdev->flags);
+ set_bit(Replacement, &rdev->flags);
+ raid1_add_conf(conf, rdev, repl_slot, true);
diff --git a/kernel-md-lbs-forward-compat.patch b/kernel-md-lbs-forward-compat.patch
index 7aa27162..d9122f47 100644
--- a/kernel-md-lbs-forward-compat.patch
+++ b/kernel-md-lbs-forward-compat.patch
@@ -11,23 +11,51 @@ super_1_load(), so such an array does not assemble here at all:
md: md_import_device returned -22
mdadm --examine calls the superblock healthy and nothing is logged, so
-the failure reads like broken disks. Upstream treats it as expected
-(a4166f1c4893): a kernel that does not know the field would assemble the
-array with a different logical block size and lose data.
+the failure reads like broken disks. This matters in practice: rescue
+media run >= 6.19 kernels, and an array created there must still
+assemble on this kernel.
-So learn the field rather than ignore it. Backport the metadata-reading
-half of 62ed1b582246: the recorded size is followed when stacking queue
-limits, exactly as >= 6.19 does, so the array comes up with the same
-logical block size on both. That is what makes assembling it here safe.
-The field is deliberately never introduced here and there is no sysfs
-knob to set it - this kernel only follows what a newer one recorded.
+Backport the metadata-reading subset of 62ed1b582246: the recorded size
+seeds each personality's queue limits exactly as on >= 6.19, so the
+array comes up with the same logical block size on both. Member devices
+can only raise it (blk_stack_limits takes the max), also as upstream.
-Also give the padding check a pr_warn (from upstream 9c47127a807d) so the
-next forward-incompatible feature is diagnosable rather than silent.
+Deliberate deviations from upstream. This kernel follows and propagates
+what the metadata already carries, but never introduces a non-zero value
+into an array whose reference superblock carries zero - only a >= 6.19
+kernel can do that:
+- no md/logical_block_size sysfs store, and mddev->logical_block_size is
+ never set from the stacked limits (upstream stamps new arrays there);
+ its only source here is the superblock itself. super_1_sync() writes
+ the field unconditionally, so it stays zero for arrays that never had
+ it and a stale value cannot survive on an individual member,
+- super_1_load() validates the recorded value (0, or a power of two in
+ [SECTOR_SIZE, PAGE_SIZE]) so on-disk garbage is rejected with a
+ message instead of reaching queue_limits validation,
+- raid5_set_limits() stops ignoring mddev_stack_rdev_limits() errors,
+ otherwise the PAGE_SIZE cap would not be enforced for raid456
+ (upstream has the same hole),
+- the padding rejection in super_1_load() gains the pr_warn from
+ upstream 9c47127a807d, without the check_new_feature bypass.
+Accepted behaviour change: the PAGE_SIZE cap applies to the stacked
+result, so an array whose member devices report a logical block size
+above PAGE_SIZE no longer starts (same as >= 6.19). With 1.x or 0.90
+metadata such members were never usable here anyway - the 4 KiB
+superblock read is not aligned to their logical block size - so this
+can only affect external-metadata setups.
+---
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
-@@ -1866,9 +1866,12 @@
+@@ -1813,6 +1813,7 @@
+ sector_t sb_start;
+ sector_t sectors;
+ int bmask;
++ u32 lbs;
+ bool spare_disk = true;
+
+ /*
+@@ -1866,9 +1867,18 @@
}
if (sb->pad0 ||
sb->pad3[0] ||
@@ -36,12 +64,18 @@ next forward-incompatible feature is diagnosable rather than silent.
/* Some padding is non-zero, might be a new feature */
+ pr_warn("md: some padding is non-zero on %pg, might be a new feature\n",
+ rdev->bdev);
++ return -EINVAL;
++ }
++ lbs = le32_to_cpu(sb->logical_block_size);
++ if (lbs && (!is_power_of_2(lbs) || lbs < SECTOR_SIZE || lbs > PAGE_SIZE)) {
++ pr_warn("md: bogus logical_block_size %u on %pg\n",
++ lbs, rdev->bdev);
return -EINVAL;
+ }
rdev->preferred_minor = 0xffff;
rdev->data_offset = le64_to_cpu(sb->data_offset);
-@@ -2009,6 +2012,7 @@
+@@ -2009,6 +2019,7 @@
mddev->layout = le32_to_cpu(sb->layout);
mddev->raid_disks = le32_to_cpu(sb->raid_disks);
mddev->dev_sectors = le64_to_cpu(sb->size);
@@ -49,40 +83,23 @@ next forward-incompatible feature is diagnosable rather than silent.
mddev->events = ev1;
mddev->bitmap_info.offset = 0;
mddev->bitmap_info.space = 0;
-@@ -2218,6 +2222,13 @@
+@@ -2218,6 +2229,8 @@
sb->chunksize = cpu_to_le32(mddev->chunk_sectors);
sb->level = cpu_to_le32(mddev->level);
sb->layout = cpu_to_le32(mddev->layout);
-+ /*
-+ * Keep an already recorded size in sync across members, but never
-+ * record one here: kernels that do not know this field reject every
-+ * superblock whose padding is non-zero.
-+ */
-+ if (mddev->logical_block_size)
-+ sb->logical_block_size = cpu_to_le32(mddev->logical_block_size);
++ /* zero for arrays that never had it - keeps unpatched kernels accepting them */
++ sb->logical_block_size = cpu_to_le32(mddev->logical_block_size);
if (test_bit(FailFast, &rdev->flags))
sb->devflags |= FailFast1;
else
-@@ -6098,6 +6109,14 @@
- {
- struct md_rdev *rdev;
-
-+ /*
-+ * Honour the size recorded by a newer kernel so the array comes up
-+ * with the same logical block size there and here. Members can only
-+ * raise it further, exactly as on those kernels.
-+ */
-+ if (mddev->logical_block_size > lim->logical_block_size)
-+ lim->logical_block_size = mddev->logical_block_size;
-+
- rdev_for_each(rdev, mddev) {
- queue_limits_stack_bdev(lim, rdev->bdev, rdev->data_offset,
- mddev->gendisk->disk_name);
-@@ -6106,6 +6125,13 @@
+@@ -6106,6 +6119,16 @@
return -EINVAL;
}
-+ /* metadata I/O is done in single pages, so it cannot exceed one */
++ /*
++ * Before RAID adding folio support, the logical_block_size
++ * should be smaller than the page size.
++ */
+ if (lim->logical_block_size > PAGE_SIZE) {
+ pr_err("%s: logical_block_size must not be larger than PAGE_SIZE\n",
+ mdname(mddev));
@@ -92,7 +109,7 @@ next forward-incompatible feature is diagnosable rather than silent.
return 0;
}
EXPORT_SYMBOL_GPL(mddev_stack_rdev_limits);
-@@ -6860,6 +6886,7 @@
+@@ -6860,6 +6883,7 @@
mddev->chunk_sectors = 0;
mddev->ctime = mddev->utime = 0;
mddev->layout = 0;
@@ -110,6 +127,74 @@ next forward-incompatible feature is diagnosable rather than silent.
__u64 events;
/* If the last 'event' was simply a clean->dirty transition, and
* we didn't write it to the spares, then it is safe and simple
+--- a/drivers/md/md-linear.c
++++ b/drivers/md/md-linear.c
+@@ -72,6 +72,7 @@
+
+ md_init_stacking_limits(&lim);
+ lim.max_hw_sectors = mddev->chunk_sectors;
++ lim.logical_block_size = mddev->logical_block_size;
+ lim.max_write_zeroes_sectors = mddev->chunk_sectors;
+ lim.max_hw_wzeroes_unmap_sectors = mddev->chunk_sectors;
+ lim.io_min = mddev->chunk_sectors << 9;
+--- a/drivers/md/raid0.c
++++ b/drivers/md/raid0.c
+@@ -385,6 +385,7 @@
+ lim.max_hw_sectors = mddev->chunk_sectors;
+ lim.max_write_zeroes_sectors = mddev->chunk_sectors;
+ lim.max_hw_wzeroes_unmap_sectors = mddev->chunk_sectors;
++ lim.logical_block_size = mddev->logical_block_size;
+ lim.io_min = mddev->chunk_sectors << 9;
+ lim.io_opt = lim.io_min * mddev->raid_disks;
+ lim.chunk_sectors = mddev->chunk_sectors;
+--- a/drivers/md/raid1.c
++++ b/drivers/md/raid1.c
+@@ -3225,6 +3225,7 @@
+ md_init_stacking_limits(&lim);
+ lim.max_write_zeroes_sectors = 0;
+ lim.max_hw_wzeroes_unmap_sectors = 0;
++ lim.logical_block_size = mddev->logical_block_size;
+ lim.features |= BLK_FEAT_ATOMIC_WRITES;
+ err = mddev_stack_rdev_limits(mddev, &lim, MDDEV_STACK_INTEGRITY);
+ if (err)
+--- a/drivers/md/raid10.c
++++ b/drivers/md/raid10.c
+@@ -4003,6 +4003,7 @@
+ md_init_stacking_limits(&lim);
+ lim.max_write_zeroes_sectors = 0;
+ lim.max_hw_wzeroes_unmap_sectors = 0;
++ lim.logical_block_size = mddev->logical_block_size;
+ lim.io_min = mddev->chunk_sectors << 9;
+ lim.chunk_sectors = mddev->chunk_sectors;
+ lim.io_opt = lim.io_min * raid10_nr_stripes(conf);
+--- a/drivers/md/raid5.c
++++ b/drivers/md/raid5.c
+@@ -7756,6 +7756,7 @@
+ struct r5conf *conf = mddev->private;
+ struct queue_limits lim;
+ int data_disks, stripe;
++ int err;
+ struct md_rdev *rdev;
+
+ /*
+@@ -7771,13 +7772,16 @@
+ stripe = roundup_pow_of_two(data_disks * (mddev->chunk_sectors << 9));
+
+ md_init_stacking_limits(&lim);
++ lim.logical_block_size = mddev->logical_block_size;
+ lim.io_min = mddev->chunk_sectors << 9;
+ lim.io_opt = lim.io_min * (conf->raid_disks - conf->max_degraded);
+ lim.features |= BLK_FEAT_RAID_PARTIAL_STRIPES_EXPENSIVE;
+ lim.discard_granularity = stripe;
+ lim.max_write_zeroes_sectors = 0;
+ lim.max_hw_wzeroes_unmap_sectors = 0;
+- mddev_stack_rdev_limits(mddev, &lim, 0);
++ err = mddev_stack_rdev_limits(mddev, &lim, 0);
++ if (err)
++ return err;
+ rdev_for_each(rdev, mddev)
+ queue_limits_stack_bdev(&lim, rdev->bdev, rdev->new_data_offset,
+ mddev->gendisk->disk_name);
--- a/include/uapi/linux/raid/md_p.h
+++ b/include/uapi/linux/raid/md_p.h
@@ -291,7 +291,8 @@
================================================================
---- gitweb:
http://git.pld-linux.org/gitweb.cgi/packages/kernel.git/commitdiff/e8f83729bef9bc7c5233c819c868b9207b330cc2
More information about the pld-cvs-commit
mailing list