md: Fix forward incompatibility from configurable logical block size

Commit 62ed1b5822 ("md: allow configuring logical block size") used
reserved pad to add 'logical_block_size' to metadata. RAID rejects
non-zero reserved pad, so arrays fail when rolling back to old kernels
after booting new ones.

Set 'logical_block_size' only for newly created arrays to support rollback
to old kernels. Importantly new arrays still won't work on old kernels to
prevent data loss issue from LBS changes.

For arrays created on old kernels which confirmed not to rollback,
configure LBS by echo current LBS (queue/logical_block_size) to
md/logical_block_size.

Fixes: 62ed1b5822 ("md: allow configuring logical block size")
Reported-by: BugReports <bugreports61@gmail.com>
Closes: https://lore.kernel.org/linux-raid/825e532d-d1e1-44bb-5581-692b7c091796@huaweicloud.com/T/#t
Signed-off-by: Li Nan <linan122@huawei.com>
Link: https://lore.kernel.org/linux-raid/20251226024221.724201-2-linan666@huaweicloud.com
Signed-off-by: Yu Kuai <yukuai@fnnas.com>
This commit is contained in:
Li Nan
2025-12-26 10:42:21 +08:00
committed by Yu Kuai
parent 864466c38c
commit a4166f1c48

View File

@@ -5980,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;
@@ -6162,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;
}