summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2025-12-31 06:55:07 -0700
committerJens Axboe <axboe@kernel.dk>2025-12-31 06:55:07 -0700
commit9e193a06e6e5b313973de316be2d16913d42f7c3 (patch)
tree0a67cc03234a06db9161b18523f0f83c7cfe3369 /drivers
parent10845a105bbcb030647a729f1716c2309da71d33 (diff)
parenta4166f1c4893a9a620507255b9d1ccab44fab189 (diff)
downloadlinux-next-9e193a06e6e5b313973de316be2d16913d42f7c3.tar.gz
linux-next-9e193a06e6e5b313973de316be2d16913d42f7c3.zip
Merge tag 'md-6.19-20251231' of gitolite.kernel.org:pub/scm/linux/kernel/git/mdraid/linux into block-6.19
Pull MD fixes from Yu Kuai: "- Fix null-pointer dereference in raid5 sysfs group_thread_cnt store (Tuo Li) - Fix possible mempool corruption during raid1 raid_disks update via sysfs (FengWei Shih) - Fix logical_block_size configuration being overwritten during super_1_validate() (Li Nan) - Fix forward incompatibility with configurable logical block size: arrays assembled on new kernels could not be assembled on kernels <=6.18 due to non-zero reserved pad rejection (Li Nan) - Fix static checker warning about iterator not incremented (Li Nan)" * tag 'md-6.19-20251231' of gitolite.kernel.org:pub/scm/linux/kernel/git/mdraid/linux: md: Fix forward incompatibility from configurable logical block size md: Fix logical_block_size configuration being overwritten md: suspend array while updating raid_disks via sysfs md/raid5: fix possible null-pointer dereferences in raid5_store_group_thread_cnt() md: Fix static checker warning in analyze_sbs
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/md.c61
-rw-r--r--drivers/md/raid5.c10
2 files changed, 56 insertions, 15 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index e5922a682953..6d73f6e196a9 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1999,7 +1999,6 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *freshest, struc
mddev->layout = le32_to_cpu(sb->layout);
mddev->raid_disks = le32_to_cpu(sb->raid_disks);
mddev->dev_sectors = le64_to_cpu(sb->size);
- mddev->logical_block_size = le32_to_cpu(sb->logical_block_size);
mddev->events = ev1;
mddev->bitmap_info.offset = 0;
mddev->bitmap_info.space = 0;
@@ -2015,6 +2014,9 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *freshest, struc
mddev->max_disks = (4096-256)/2;
+ if (!mddev->logical_block_size)
+ mddev->logical_block_size = le32_to_cpu(sb->logical_block_size);
+
if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) &&
mddev->bitmap_info.file == NULL) {
mddev->bitmap_info.offset =
@@ -3882,7 +3884,6 @@ out_free_rdev:
static int analyze_sbs(struct mddev *mddev)
{
- int i;
struct md_rdev *rdev, *freshest, *tmp;
freshest = NULL;
@@ -3909,11 +3910,9 @@ static int analyze_sbs(struct mddev *mddev)
super_types[mddev->major_version].
validate_super(mddev, NULL/*freshest*/, freshest);
- i = 0;
rdev_for_each_safe(rdev, tmp, mddev) {
if (mddev->max_disks &&
- (rdev->desc_nr >= mddev->max_disks ||
- i > mddev->max_disks)) {
+ rdev->desc_nr >= mddev->max_disks) {
pr_warn("md: %s: %pg: only %d devices permitted\n",
mdname(mddev), rdev->bdev,
mddev->max_disks);
@@ -4407,7 +4406,7 @@ raid_disks_store(struct mddev *mddev, const char *buf, size_t len)
if (err < 0)
return err;
- err = mddev_lock(mddev);
+ err = mddev_suspend_and_lock(mddev);
if (err)
return err;
if (mddev->pers)
@@ -4432,7 +4431,7 @@ raid_disks_store(struct mddev *mddev, const char *buf, size_t len)
} else
mddev->raid_disks = n;
out_unlock:
- mddev_unlock(mddev);
+ mddev_unlock_and_resume(mddev);
return err ? err : len;
}
static struct md_sysfs_entry md_raid_disks =
@@ -5981,13 +5980,33 @@ lbs_store(struct mddev *mddev, const char *buf, size_t len)
if (mddev->major_version == 0)
return -EINVAL;
- if (mddev->pers)
- return -EBUSY;
-
err = kstrtouint(buf, 10, &lbs);
if (err < 0)
return -EINVAL;
+ if (mddev->pers) {
+ unsigned int curr_lbs;
+
+ if (mddev->logical_block_size)
+ return -EBUSY;
+ /*
+ * To fix forward compatibility issues, LBS is not
+ * configured for arrays from old kernels (<=6.18) by default.
+ * If the user confirms no rollback to old kernels,
+ * enable LBS by writing current LBS — to prevent data
+ * loss from LBS changes.
+ */
+ curr_lbs = queue_logical_block_size(mddev->gendisk->queue);
+ if (lbs != curr_lbs)
+ return -EINVAL;
+
+ mddev->logical_block_size = curr_lbs;
+ set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
+ pr_info("%s: logical block size configured successfully, array will not be assembled in old kernels (<= 6.18)\n",
+ mdname(mddev));
+ return len;
+ }
+
err = mddev_lock(mddev);
if (err)
goto unlock;
@@ -6163,7 +6182,27 @@ int mddev_stack_rdev_limits(struct mddev *mddev, struct queue_limits *lim,
mdname(mddev));
return -EINVAL;
}
- mddev->logical_block_size = lim->logical_block_size;
+
+ /* Only 1.x meta needs to set logical block size */
+ if (mddev->major_version == 0)
+ return 0;
+
+ /*
+ * Fix forward compatibility issue. Only set LBS by default for
+ * new arrays, mddev->events == 0 indicates the array was just
+ * created. When assembling an array, read LBS from the superblock
+ * instead — LBS is 0 in superblocks created by old kernels.
+ */
+ if (!mddev->events) {
+ pr_info("%s: array will not be assembled in old kernels that lack configurable LBS support (<= 6.18)\n",
+ mdname(mddev));
+ mddev->logical_block_size = lim->logical_block_size;
+ }
+
+ if (!mddev->logical_block_size)
+ pr_warn("%s: echo current LBS to md/logical_block_size to prevent data loss issues from LBS changes.\n"
+ "\tNote: After setting, array will not be assembled in old kernels (<= 6.18)\n",
+ mdname(mddev));
return 0;
}
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index e57ce3295292..8dc98f545969 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -7187,12 +7187,14 @@ raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len)
err = mddev_suspend_and_lock(mddev);
if (err)
return err;
+ conf = mddev->private;
+ if (!conf) {
+ mddev_unlock_and_resume(mddev);
+ return -ENODEV;
+ }
raid5_quiesce(mddev, true);
- conf = mddev->private;
- if (!conf)
- err = -ENODEV;
- else if (new != conf->worker_cnt_per_group) {
+ if (new != conf->worker_cnt_per_group) {
old_groups = conf->worker_groups;
if (old_groups)
flush_workqueue(raid5_wq);