Support for RAID10 with +4 disks in IMSM introduced an inconsistency
between the VROC UEFI driver and Linux IMSM. VROC UEFI does not
support RAID10 with +4 disks, therefore appropriate protections were
added to the mdadm IMSM code that results in skipping processing of
such RAID in the UEFI phase. Unfortunately the case of migration
RAID0 2 disks to RAID10 4 disks was omitted, this case requires
maintaining compatibility with the VROC UEFI driver because it is
supported.
For RAID10 +4 disk the MPB_ATTRIB_RAID10_EXT attribute is set in the
metadata, thanks to which the UEFI driver does not process such RAID.
In the series adding support, a new metadata raid level value
IMSM_T_RAID10 was also introduced. It is not recognized by VROC UEFI.
The issue is caused by the fact that in the case of the mentioned
migration, IMSM_T_RAID10 is entered into the metadata but attribute
MPB_ATTRIB_RAID10_EXT is not entered, which causes an attempt to
process such RAID in the UEFI phase. This situation results in
the platform hang during booting in UEFI phase, this also results in
data loss after failed and interrupted RAID processing in VROC UEFI.
The above situation is result of the update_imsm_raid_level()
function, for the mentioned migration function is executed on a map
with a not yet updated number of disks.
The fix is to explicitly handle migration in the function mentioned
above to maintain compatibility with VROC UEFI driver.
Steps to reproduce:
mdadm -C /dev/md/imsm0 -e imsm -n 2 /dev/nvme[1,2]n1 -R
mdadm -C /dev/md/vol -l 0 -n 2 /dev/nvme[1,2]n1 --assume-clean -R
mdadm -a /dev/md127 /dev/nvme3n1
mdadm -a /dev/md127 /dev/nvme4n1
mdadm -G /dev/md126 -l 10
reboot
Fixes: 27550b13297a ("imsm: add support for literal RAID 10")
Signed-off-by: Blazej Kucman <blazej.kucman@intel.com>
return;
}
+ /*
+ * RAID0 to RAID10 migration.
+ * Due to the compatibility with VROC UEFI must be maintained, this case must be handled
+ * separately, because the map does not have an updated number of disks.
+ */
+ if (map->raid_level == IMSM_T_RAID0) {
+ if (map->num_members == 2)
+ map->raid_level = IMSM_T_RAID1;
+ else
+ map->raid_level = IMSM_T_RAID10;
+ return;
+ }
+
if (map->num_members == 4) {
if (map->raid_level == IMSM_T_RAID10 || map->raid_level == IMSM_T_RAID1)
return;