]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
md: Fix forward incompatibility from configurable logical block size
authorLi Nan <linan122@huawei.com>
Fri, 26 Dec 2025 02:42:21 +0000 (10:42 +0800)
committerYu Kuai <yukuai@fnnas.com>
Sat, 27 Dec 2025 02:14:07 +0000 (10:14 +0800)
Commit 62ed1b582246 ("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: 62ed1b582246 ("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>
drivers/md/md.c

index a13f92a64df6b2a110f7d4d16b2b14d3d4066992..6d73f6e196a9f94fc128748b931d68d8e96a932a 100644 (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;
 }