]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Allow RAID0 to be created with v0.90 metadata #161
authorNeilBrown <neil@brown.name>
Fri, 4 Apr 2025 00:56:04 +0000 (11:56 +1100)
committerMariusz Tkaczyk <mtkaczyk@kernel.org>
Thu, 10 Apr 2025 09:35:36 +0000 (11:35 +0200)
It is not currently possible to create a RAID0 with 0.90 metadata.
This is because 0.90 cannot specify the layout of RAID0 (it is
traditionally ignored) and different kernels do different things with
RAID0 layouts.

However it should be possible to use --layout=dangerous as that
acknowledges the risk.
It also should be possible to create a RAID0 with all devices the same
size because in that case all layouts are identical.

The metadata handler can only check that all devices are the same size
quite late - in write_init_super().  By that time the default is
currently set - set to a value that super0 cannot handle.

So this patch delays the setting of the default value and leave it for
the metadata handler (or for the Build handler).

super1 selects ORIG in that case.
intel and ddf don't support non-uniform RAID0 so they don't need any
change.
super0 now checks the sizes of devices if the default RAID0 layout was
requested and rejects the request in they are not the same.

validiate_geometry0 now allows "dangerous" layouts for raid0.

Signed-off-by: NeilBrown <neil@brown.name>
Build.c
Create.c
maps.c
mdadm.h
super0.c
super1.c
tests/00raid0

diff --git a/Build.c b/Build.c
index 70aab7a03375d630f2da94ccff9dfe420098f7fd..9eb85a13ddc63def98a468c75f5f42d1a383949f 100644 (file)
--- a/Build.c
+++ b/Build.c
@@ -103,6 +103,10 @@ int Build(struct mddev_ident *ident, struct mddev_dev *devlist, struct shape *s,
                s->chunk = 64;
        array.chunk_size = s->chunk*1024;
        array.layout = s->layout;
+
+       if (array.level == 0 && array.layout == UnSet)
+               /* Raid0 leaves default to metadata handler.  That is us. */
+               array.layout = RAID0_ORIG_LAYOUT;
        if (md_set_array_info(mdfd, &array)) {
                pr_err("md_set_array_info() failed for %s: %s\n", chosen_name, strerror(errno));
                goto abort;
index fd6c9215202112b747fbaca3a3172c93b270e06a..2b181dbf820ea9adf414906d8b2eb0e4f9f364b8 100644 (file)
--- a/Create.c
+++ b/Create.c
@@ -77,7 +77,7 @@ int default_layout(struct supertype *st, int level, int verbose)
                layout = 0;
                break;
        case 0:
-               layout = RAID0_ORIG_LAYOUT;
+               /* Leave unset - metadata handlers choose default */
                break;
        case 10:
                layout = 0x102; /* near=2, far=1 */
diff --git a/maps.c b/maps.c
index 17f8b54dc40ffd3c657c41472c516c6a405840e1..2181b4aca2fef3c5c0807f542db4c029de145f35 100644 (file)
--- a/maps.c
+++ b/maps.c
@@ -81,7 +81,7 @@ mapping_t r0layout[] = {
        { "alternate", RAID0_ALT_MULTIZONE_LAYOUT},
        { "1", 1}, /* aka ORIG */
        { "2", 2}, /* aka ALT */
-       { "dangerous", 0},
+       { "dangerous", RAID0_DANGEROUS_LAYOUT},
        { NULL, UnSet},
 };
 
diff --git a/mdadm.h b/mdadm.h
index e84c341c30403c484d95066834baf4aa183d0f1a..0ea83ad3cdb6b65d0cf0ea0a386e9e1c72d882b7 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -2003,6 +2003,7 @@ static inline int xasprintf(char **strp, const char *fmt, ...) {
 #endif
 
 enum r0layout {
+       RAID0_DANGEROUS_LAYOUT = 0, /* layout depends on kernel version */
        RAID0_ORIG_LAYOUT = 1,
        RAID0_ALT_MULTIZONE_LAYOUT = 2,
 };
index ff4905b964112f899987e3c1cb67ba43eb84dbe7..4a462bdca9c882c63582f300bd5a7e76c06e1fce 100644 (file)
--- a/super0.c
+++ b/super0.c
@@ -837,6 +837,7 @@ struct devinfo {
        int fd;
        char *devname;
        mdu_disk_info_t disk;
+       unsigned long long dev_size;
        struct devinfo *next;
 };
 
@@ -866,6 +867,10 @@ static int add_to_super0(struct supertype *st, mdu_disk_info_t *dinfo,
        di->devname = devname;
        di->disk = *dinfo;
        di->next = NULL;
+
+       if (is_fd_valid(fd))
+               get_dev_size(fd, NULL, &di->dev_size);
+
        *dip = di;
 
        return 0;
@@ -929,6 +934,33 @@ static int write_init_super0(struct supertype *st)
        int rv = 0;
        struct devinfo *di;
 
+       if (sb->level == 0 && sb->layout == UnSet) {
+               /* Without requesting a dangerous (0) layout
+                * we can only allow this RAID0 if all devices are
+                * the same size
+                */
+               unsigned long long chunks = 0;
+               unsigned long chunk_sectors = sb->chunk_size >> 9;
+
+               for (di = st->info; di; di = di->next) {
+                       unsigned long long this_chunks;
+
+                       this_chunks = st->ss->avail_size(st, di->dev_size, 0) / chunk_sectors;
+
+                       if (chunks == 0) {
+                               chunks = this_chunks;
+                               continue;
+                       }
+
+                       if (this_chunks != chunks) {
+                               pr_err("Need explicit layout=dangerous to create 0.90 raid0 on non-uniform sized devices\n");
+                               return 1;
+                       }
+               }
+               /* looks safe */
+               sb->layout = 0;
+       }
+
        for (di = st->info ; di && ! rv ; di = di->next) {
 
                if (di->disk.state & (1 << MD_DISK_FAULTY))
@@ -1321,7 +1353,7 @@ static int validate_geometry0(struct supertype *st, int level,
        if (*chunk == UnSet)
                *chunk = DEFAULT_CHUNK;
 
-       if (level == 0 && layout != UnSet) {
+       if (level == 0 && layout != UnSet && layout != RAID0_DANGEROUS_LAYOUT) {
                if (verbose)
                        pr_err("0.90 metadata does not support layouts for RAID0\n");
                return 0;
index c828b68272fd7efb3b0147205d2b35e6d754c74e..fb93f462cc953f7878a4874e1372eb125aa62a2a 100644 (file)
--- a/super1.c
+++ b/super1.c
@@ -1677,6 +1677,10 @@ static int init_super1(struct supertype *st, mdu_array_info_t *info,
                       sizeof(sb->set_name) - namelen);
        }
 
+       if (info->level == 0 && info->layout == UnSet)
+               /* Metadata chooses default layout for RAID0 */
+               info->layout = RAID0_ORIG_LAYOUT;
+
        sb->ctime = __cpu_to_le64((unsigned long long)time(0));
        sb->level = __cpu_to_le32(info->level);
        sb->layout = __cpu_to_le32(info->layout);
index 6407c320fd65ccd743adbd0fb42b3df90a4836be..94abcd492f78fd188575f5559243d05bfaa7408f 100644 (file)
@@ -6,8 +6,8 @@ check raid0
 testdev $md0 3 $mdsize2_l 512
 mdadm -S $md0
 
-# verify raid0 with layouts fail for 0.90
-mdadm -CR $md0 -e0.90 -l0 -n4 $dev0 $dev1 $dev2 $dev3
+# verify raid0 with explicit layouts fail for 0.90
+mdadm -CR $md0 -e0.90 -l0 --layout=original -n4 $dev0 $dev1 $dev2 $dev3
 check opposite_result
 
 # now with no superblock