]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super1.c
Create.c: fix uclibc build
[thirdparty/mdadm.git] / super1.c
index cedbb53b4f2ef8dbe6a7aa5aee3ba01a3a645990..81d29a652f3645d7596c7026716b2e596aafd701 100644 (file)
--- a/super1.c
+++ b/super1.c
@@ -192,7 +192,7 @@ static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb)
        unsigned int disk_csum, csum;
        unsigned long long newcsum;
        int size = sizeof(*sb) + __le32_to_cpu(sb->max_dev)*2;
-       unsigned int *isuper = (unsigned int*)sb;
+       unsigned int *isuper = (unsigned int *)sb;
 
 /* make sure I can count... */
        if (offsetof(struct mdp_superblock_1,data_offset) != 128 ||
@@ -204,7 +204,7 @@ static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb)
        disk_csum = sb->sb_csum;
        sb->sb_csum = 0;
        newcsum = 0;
-       for (; size>=4; size -= 4 ) {
+       for (; size >= 4; size -= 4) {
                newcsum += __le32_to_cpu(*isuper);
                isuper++;
        }
@@ -319,7 +319,7 @@ static inline unsigned int choose_ppl_space(int chunk)
 static void examine_super1(struct supertype *st, char *homehost)
 {
        struct mdp_superblock_1 *sb = st->sb;
-       bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb)+MAX_SB_SIZE);
+       bitmap_super_t *bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE);
        time_t atime;
        unsigned int d;
        int role;
@@ -330,6 +330,7 @@ static void examine_super1(struct supertype *st, char *homehost)
        int layout;
        unsigned long long sb_offset;
        struct mdinfo info;
+       int inconsistent = 0;
 
        printf("          Magic : %08x\n", __le32_to_cpu(sb->magic));
        printf("        Version : 1");
@@ -342,8 +343,9 @@ static void examine_super1(struct supertype *st, char *homehost)
                printf(".0\n");
        printf("    Feature Map : 0x%x\n", __le32_to_cpu(sb->feature_map));
        printf("     Array UUID : ");
-       for (i=0; i<16; i++) {
-               if ((i&3)==0 && i != 0) printf(":");
+       for (i = 0; i < 16; i++) {
+               if ((i & 3) == 0 && i != 0)
+                       printf(":");
                printf("%02x", sb->set_uuid[i]);
        }
        printf("\n");
@@ -405,15 +407,21 @@ static void examine_super1(struct supertype *st, char *homehost)
 
        st->ss->getinfo_super(st, &info, NULL);
        if (info.space_after != 1 &&
-           !(__le32_to_cpu(sb->feature_map) & MD_FEATURE_NEW_OFFSET))
-               printf("   Unused Space : before=%llu sectors, after=%llu sectors\n",
-                      info.space_before, info.space_after);
-
-       printf("          State : %s\n",
-              (__le64_to_cpu(sb->resync_offset)+1)? "active":"clean");
+           !(__le32_to_cpu(sb->feature_map) & MD_FEATURE_NEW_OFFSET)) {
+               printf("   Unused Space : before=%llu sectors, ",
+                      info.space_before);
+               if (info.space_after < INT64_MAX)
+                       printf("after=%llu sectors\n", info.space_after);
+               else
+                       printf("after=-%llu sectors DEVICE TOO SMALL\n",
+                              UINT64_MAX - info.space_after);
+       }
+       printf("          State : %s%s\n",
+              (__le64_to_cpu(sb->resync_offset) + 1) ? "active":"clean",
+              (info.space_after > INT64_MAX)       ? " TRUNCATED DEVICE" : "");
        printf("    Device UUID : ");
-       for (i=0; i<16; i++) {
-               if ((i&3)==0 && i != 0)
+       for (i = 0; i < 16; i++) {
+               if ((i & 3)==0 && i != 0)
                        printf(":");
                printf("%02x", sb->device_uuid[i]);
        }
@@ -536,26 +544,6 @@ static void examine_super1(struct supertype *st, char *homehost)
                break;
        }
        printf("\n");
-#if 0
-       /* This turns out to just be confusing */
-       printf("    Array Slot : %d (", __le32_to_cpu(sb->dev_number));
-       for (i = __le32_to_cpu(sb->max_dev); i> 0 ; i--)
-               if (__le16_to_cpu(sb->dev_roles[i-1]) != MD_DISK_ROLE_SPARE)
-                       break;
-       for (d = 0; d < i; d++) {
-               int role = __le16_to_cpu(sb->dev_roles[d]);
-               if (d)
-                       printf(", ");
-               if (role == MD_DISK_ROLE_SPARE)
-                       printf("empty");
-               else
-                       if(role == MD_DISK_ROLE_FAULTY)
-                               printf("failed");
-                       else
-                               printf("%d", role);
-       }
-       printf(")\n");
-#endif
        printf("   Device Role : ");
        role = role_from_sb(sb);
        if (role >= MD_DISK_ROLE_FAULTY)
@@ -576,28 +564,36 @@ static void examine_super1(struct supertype *st, char *homehost)
                        if (role == d)
                                cnt++;
                }
-               if (cnt == 2)
+               if (cnt == 2 && __le32_to_cpu(sb->level) > 0)
                        printf("R");
                else if (cnt == 1)
                        printf("A");
                else if (cnt == 0)
                        printf(".");
-               else
+               else {
                        printf("?");
+                       inconsistent = 1;
+               }
        }
-#if 0
-       /* This is confusing too */
-       faulty = 0;
-       for (i = 0; i< __le32_to_cpu(sb->max_dev); i++) {
-               int role = __le16_to_cpu(sb->dev_roles[i]);
-               if (role == MD_DISK_ROLE_FAULTY)
-                       faulty++;
-       }
-       if (faulty)
-               printf(" %d failed", faulty);
-#endif
        printf(" ('A' == active, '.' == missing, 'R' == replacing)");
        printf("\n");
+       for (d = 0; d < __le32_to_cpu(sb->max_dev); d++) {
+               unsigned int r = __le16_to_cpu(sb->dev_roles[d]);
+               if (r <= MD_DISK_ROLE_MAX &&
+                   r > __le32_to_cpu(sb->raid_disks) + delta_extra)
+                       inconsistent = 1;
+       }
+       if (inconsistent) {
+               printf("WARNING Array state is inconsistent - each number should appear only once\n");
+               for (d = 0; d < __le32_to_cpu(sb->max_dev); d++)
+                       if (__le16_to_cpu(sb->dev_roles[d]) >=
+                           MD_DISK_ROLE_FAULTY)
+                               printf(" %d:-", d);
+                       else
+                               printf(" %d:%d", d,
+                                      __le16_to_cpu(sb->dev_roles[d]));
+               printf("\n");
+       }
 }
 
 static void brief_examine_super1(struct supertype *st, int verbose)
@@ -618,8 +614,7 @@ static void brief_examine_super1(struct supertype *st, int verbose)
 
        printf("ARRAY ");
        if (nm) {
-               printf("/dev/md/");
-               print_escape(nm);
+               printf(DEV_MD_DIR "%s", nm);
                putchar(' ');
        }
        if (verbose && c)
@@ -635,14 +630,10 @@ static void brief_examine_super1(struct supertype *st, int verbose)
                printf("num-devices=%d ", __le32_to_cpu(sb->raid_disks));
        printf("UUID=");
        for (i = 0; i < 16; i++) {
-               if ((i&3)==0 && i != 0)
+               if ((i & 3)==0 && i != 0)
                        printf(":");
                printf("%02x", sb->set_uuid[i]);
        }
-       if (sb->set_name[0]) {
-               printf(" name=");
-               print_quoted(sb->set_name);
-       }
        printf("\n");
 }
 
@@ -653,7 +644,7 @@ static void export_examine_super1(struct supertype *st)
        int len = 32;
        int layout;
 
-       printf("MD_LEVEL=%s\n", map_num(pers, __le32_to_cpu(sb->level)));
+       printf("MD_LEVEL=%s\n", map_num_s(pers, __le32_to_cpu(sb->level)));
        printf("MD_DEVICES=%d\n", __le32_to_cpu(sb->raid_disks));
        for (i = 0; i < 32; i++)
                if (sb->set_name[i] == '\n' || sb->set_name[i] == '\0') {
@@ -689,7 +680,7 @@ static void export_examine_super1(struct supertype *st)
        }
        printf("MD_UUID=");
        for (i = 0; i < 16; i++) {
-               if ((i&3) == 0 && i != 0)
+               if ((i & 3) == 0 && i != 0)
                        printf(":");
                printf("%02x", sb->set_uuid[i]);
        }
@@ -698,7 +689,7 @@ static void export_examine_super1(struct supertype *st)
               __le64_to_cpu(sb->utime) & 0xFFFFFFFFFFULL);
        printf("MD_DEV_UUID=");
        for (i = 0; i < 16; i++) {
-               if ((i&3) == 0 && i != 0)
+               if ((i & 3) == 0 && i != 0)
                        printf(":");
                printf("%02x", sb->device_uuid[i]);
        }
@@ -788,7 +779,7 @@ static int copy_metadata1(struct supertype *st, int from, int to)
                                /* have the header, can calculate
                                 * correct bitmap bytes */
                                bitmap_super_t *bms;
-                               bms = (void*)buf;
+                               bms = (void *)buf;
                                bytes = calc_bitmap_size(bms, 512);
                                if (n > bytes)
                                        n =  bytes;
@@ -843,7 +834,7 @@ err:
 static void detail_super1(struct supertype *st, char *homehost, char *subarray)
 {
        struct mdp_superblock_1 *sb = st->sb;
-       bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE);
+       bitmap_super_t *bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE);
        int i;
        int l = homehost ? strlen(homehost) : 0;
 
@@ -856,7 +847,7 @@ static void detail_super1(struct supertype *st, char *homehost, char *subarray)
                printf("\n      Cluster Name : %-64s", bms->cluster_name);
        printf("\n              UUID : ");
        for (i = 0; i < 16; i++) {
-               if ((i&3) == 0 && i != 0)
+               if ((i & 3) == 0 && i != 0)
                        printf(":");
                printf("%02x", sb->set_uuid[i]);
        }
@@ -869,10 +860,6 @@ static void brief_detail_super1(struct supertype *st, char *subarray)
        struct mdp_superblock_1 *sb = st->sb;
        int i;
 
-       if (sb->set_name[0]) {
-               printf(" name=");
-               print_quoted(sb->set_name);
-       }
        printf(" UUID=");
        for (i = 0; i < 16; i++) {
                if ((i & 3) == 0 && i != 0)
@@ -915,7 +902,7 @@ static int examine_badblocks_super1(struct supertype *st, int fd, char *devname)
        }
 
        size = __le16_to_cpu(sb->bblog_size)* 512;
-       if (posix_memalign((void**)&bbl, 4096, size) != 0) {
+       if (posix_memalign((void **)&bbl, 4096, size) != 0) {
                pr_err("could not allocate badblocks list\n");
                return 0;
        }
@@ -963,7 +950,7 @@ static int match_home1(struct supertype *st, char *homehost)
 static void uuid_from_super1(struct supertype *st, int uuid[4])
 {
        struct mdp_superblock_1 *super = st->sb;
-       char *cuuid = (char*)uuid;
+       char *cuuid = (char *)uuid;
        int i;
        for (i = 0; i < 16; i++)
                cuuid[i] = super->set_uuid[i];
@@ -972,9 +959,9 @@ static void uuid_from_super1(struct supertype *st, int uuid[4])
 static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map)
 {
        struct mdp_superblock_1 *sb = st->sb;
-       struct bitmap_super_s *bsb = (void*)(((char*)sb)+MAX_SB_SIZE);
+       struct bitmap_super_s *bsb = (void *)(((char *)sb) + MAX_SB_SIZE);
        struct misc_dev_info *misc =
-               (void*)(((char*)sb)+MAX_SB_SIZE+BM_SUPER_SIZE);
+               (void *)(((char *)sb) + MAX_SB_SIZE+BM_SUPER_SIZE);
        int working = 0;
        unsigned int i;
        unsigned int role;
@@ -1142,7 +1129,7 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map)
        info->recovery_blocked = info->reshape_active;
 
        if (map)
-               for (i=0; i<map_disks; i++)
+               for (i = 0; i < map_disks; i++)
                        map[i] = 0;
        for (i = 0; i < __le32_to_cpu(sb->max_dev); i++) {
                role = __le16_to_cpu(sb->dev_roles[i]);
@@ -1184,7 +1171,7 @@ static struct mdinfo *container_content1(struct supertype *st, char *subarray)
 }
 
 static int update_super1(struct supertype *st, struct mdinfo *info,
-                        char *update, char *devname, int verbose,
+                        enum update_opt update, char *devname, int verbose,
                         int uuid_set, char *homehost)
 {
        /* NOTE: for 'assemble' and 'force' we need to return non-zero
@@ -1193,31 +1180,56 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
         */
        int rv = 0;
        struct mdp_superblock_1 *sb = st->sb;
-       bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE);
+       bitmap_super_t *bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE);
 
-       if (strcmp(update, "homehost") == 0 &&
-           homehost) {
-               /* Note that 'homehost' is special as it is really
+       if (update == UOPT_HOMEHOST && homehost) {
+               /*
+                * Note that 'homehost' is special as it is really
                 * a "name" update.
                 */
                char *c;
-               update = "name";
+               update = UOPT_NAME;
                c = strchr(sb->set_name, ':');
                if (c)
-                       strncpy(info->name, c+1, 31 - (c-sb->set_name));
+                       snprintf(info->name, sizeof(info->name), "%s", c + 1);
                else
-                       strncpy(info->name, sb->set_name, 32);
-               info->name[32] = 0;
+                       snprintf(info->name, sizeof(info->name), "%s",
+                                sb->set_name);
        }
 
-       if (strcmp(update, "force-one")==0) {
+       switch (update) {
+       case UOPT_NAME: {
+               int namelen;
+
+               if (!info->name[0])
+                       snprintf(info->name, sizeof(info->name), "%d", info->array.md_minor);
+               memset(sb->set_name, 0, sizeof(sb->set_name));
+
+               namelen = strnlen(homehost, MD_NAME_MAX) + 1 + strnlen(info->name, MD_NAME_MAX);
+               if (homehost &&
+                   strchr(info->name, ':') == NULL &&
+                   namelen < MD_NAME_MAX) {
+                       strcpy(sb->set_name, homehost);
+                       strcat(sb->set_name, ":");
+                       strcat(sb->set_name, info->name);
+               } else {
+                       namelen = min((int)strnlen(info->name, MD_NAME_MAX),
+                                     (int)sizeof(sb->set_name) - 1);
+                       memcpy(sb->set_name, info->name, namelen);
+                       memset(&sb->set_name[namelen], '\0',
+                              sizeof(sb->set_name) - namelen);
+               }
+               break;
+       }
+       case UOPT_SPEC_FORCE_ONE:
                /* Not enough devices for a working array,
                 * so bring this one up-to-date
                 */
                if (sb->events != __cpu_to_le64(info->events))
                        rv = 1;
                sb->events = __cpu_to_le64(info->events);
-       } else if (strcmp(update, "force-array")==0) {
+               break;
+       case UOPT_SPEC_FORCE_ARRAY:
                /* Degraded array and 'force' requests to
                 * maybe need to mark it 'clean'.
                 */
@@ -1230,7 +1242,8 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                                rv = 1;
                        sb->resync_offset = MaxSector;
                }
-       } else if (strcmp(update, "assemble")==0) {
+               break;
+       case UOPT_SPEC_ASSEMBLE: {
                int d = info->disk.number;
                int want;
                if (info->disk.state & (1<<MD_DISK_ACTIVE))
@@ -1263,20 +1276,28 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                                __cpu_to_le64(info->reshape_progress);
                        rv = 1;
                }
-       } else if (strcmp(update, "linear-grow-new") == 0) {
-               unsigned int i;
+               break;
+       }
+       case UOPT_SPEC_LINEAR_GROW_NEW: {
+               int i;
                int fd;
-               unsigned int max = __le32_to_cpu(sb->max_dev);
+               int max = __le32_to_cpu(sb->max_dev);
+
+               if (max > MAX_DEVS)
+                       return -2;
 
                for (i = 0; i < max; i++)
                        if (__le16_to_cpu(sb->dev_roles[i]) >=
                            MD_DISK_ROLE_FAULTY)
                                break;
+               if (i != info->disk.number)
+                       return -2;
                sb->dev_number = __cpu_to_le32(i);
-               info->disk.number = i;
-               if (i >= max) {
-                       sb->max_dev = __cpu_to_le32(max+1);
-               }
+
+               if (i == max)
+                       sb->max_dev = __cpu_to_le32(max + 1);
+               if (i > max)
+                       return -2;
 
                random_uuid(sb->device_uuid);
 
@@ -1293,32 +1314,45 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                                sb->data_size = __cpu_to_le64(
                                        ds - __le64_to_cpu(sb->data_offset));
                        } else {
-                               ds -= 8*2;
-                               ds &= ~(unsigned long long)(4*2-1);
+                               ds -= 8 * 2;
+                               ds &= ~(unsigned long long)(4 * 2 - 1);
                                sb->super_offset = __cpu_to_le64(ds);
                                sb->data_size = __cpu_to_le64(
                                        ds - __le64_to_cpu(sb->data_offset));
                        }
                }
-       } else if (strcmp(update, "linear-grow-update") == 0) {
+               break;
+       }
+       case UOPT_SPEC_LINEAR_GROW_UPDATE: {
                int max = __le32_to_cpu(sb->max_dev);
+               int i = info->disk.number;
+               if (max > MAX_DEVS || i > MAX_DEVS)
+                       return -2;
+               if (i > max)
+                       return -2;
+               if (i == max)
+                       sb->max_dev = __cpu_to_le32(max + 1);
                sb->raid_disks = __cpu_to_le32(info->array.raid_disks);
-               if (info->array.raid_disks > max) {
-                       sb->max_dev = __cpu_to_le32(max+1);
-               }
                sb->dev_roles[info->disk.number] =
                        __cpu_to_le16(info->disk.raid_disk);
-       } else if (strcmp(update, "resync") == 0) {
+               break;
+       }
+       case UOPT_RESYNC:
                /* make sure resync happens */
-               sb->resync_offset = 0ULL;
-       } else if (strcmp(update, "uuid") == 0) {
+               sb->resync_offset = 0;
+               break;
+       case UOPT_UUID:
                copy_uuid(sb->set_uuid, info->uuid, super1.swapuuid);
 
                if (__le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET)
                        memcpy(bms->uuid, sb->set_uuid, 16);
-       } else if (strcmp(update, "no-bitmap") == 0) {
+               break;
+       case UOPT_NO_BITMAP:
                sb->feature_map &= ~__cpu_to_le32(MD_FEATURE_BITMAP_OFFSET);
-       } else if (strcmp(update, "bbl") == 0) {
+               if (bms->version == BITMAP_MAJOR_CLUSTERED && !IsBitmapDirty(devname))
+                       sb->resync_offset = MaxSector;
+               break;
+       case UOPT_BBL: {
                /* only possible if there is room after the bitmap, or if
                 * there is no bitmap
                 */
@@ -1347,14 +1381,12 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                                bb_offset = bitmap_offset + bm_sectors;
                        while (bb_offset < (long)sb_offset + 8 + 32*2 &&
                               bb_offset + 8+8 <= (long)data_offset)
-                               /* too close to bitmap, and room to grow */
                                bb_offset += 8;
                        if (bb_offset + 8 <= (long)data_offset) {
                                sb->bblog_size = __cpu_to_le16(8);
                                sb->bblog_offset = __cpu_to_le32(bb_offset);
                        }
                } else {
-                       /* 1.0 - Put bbl just before super block */
                        if (bm_sectors && bitmap_offset < 0)
                                space = -bitmap_offset - bm_sectors;
                        else
@@ -1365,7 +1397,9 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                                sb->bblog_offset = __cpu_to_le32((unsigned)-8);
                        }
                }
-       } else if (strcmp(update, "no-bbl") == 0) {
+               break;
+       }
+       case UOPT_NO_BBL:
                if (sb->feature_map & __cpu_to_le32(MD_FEATURE_BAD_BLOCKS))
                        pr_err("Cannot remove active bbl from %s\n",devname);
                else {
@@ -1373,12 +1407,14 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                        sb->bblog_shift = 0;
                        sb->bblog_offset = 0;
                }
-       } else if (strcmp(update, "force-no-bbl") == 0) {
+               break;
+       case UOPT_FORCE_NO_BBL:
                sb->feature_map &= ~ __cpu_to_le32(MD_FEATURE_BAD_BLOCKS);
                sb->bblog_size = 0;
                sb->bblog_shift = 0;
                sb->bblog_offset = 0;
-       } else if (strcmp(update, "ppl") == 0) {
+               break;
+       case UOPT_PPL: {
                unsigned long long sb_offset = __le64_to_cpu(sb->super_offset);
                unsigned long long data_offset = __le64_to_cpu(sb->data_offset);
                unsigned long long data_size = __le64_to_cpu(sb->data_size);
@@ -1428,37 +1464,26 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                sb->ppl.offset = __cpu_to_le16(offset);
                sb->ppl.size = __cpu_to_le16(space);
                sb->feature_map |= __cpu_to_le32(MD_FEATURE_PPL);
-       } else if (strcmp(update, "no-ppl") == 0) {
+               break;
+       }
+       case UOPT_NO_PPL:
                sb->feature_map &= ~__cpu_to_le32(MD_FEATURE_PPL |
                                                   MD_FEATURE_MUTLIPLE_PPLS);
-       } else if (strcmp(update, "name") == 0) {
-               if (info->name[0] == 0)
-                       sprintf(info->name, "%d", info->array.md_minor);
-               memset(sb->set_name, 0, sizeof(sb->set_name));
-               if (homehost &&
-                   strchr(info->name, ':') == NULL &&
-                   strlen(homehost)+1+strlen(info->name) < 32) {
-                       strcpy(sb->set_name, homehost);
-                       strcat(sb->set_name, ":");
-                       strcat(sb->set_name, info->name);
-               } else {
-                       int namelen;
-
-                       namelen = min((int)strlen(info->name),
-                                     (int)sizeof(sb->set_name) - 1);
-                       memcpy(sb->set_name, info->name, namelen);
-                       memset(&sb->set_name[namelen], '\0',
-                              sizeof(sb->set_name) - namelen);
-               }
-       } else if (strcmp(update, "devicesize") == 0 &&
-                  __le64_to_cpu(sb->super_offset) <
-                  __le64_to_cpu(sb->data_offset)) {
-               /* set data_size to device size less data_offset */
+               break;
+       case UOPT_DEVICESIZE:
+               if (__le64_to_cpu(sb->super_offset) >=
+                   __le64_to_cpu(sb->data_offset))
+                       break;
+               /*
+                * set data_size to device size less data_offset
+                */
                struct misc_dev_info *misc = (struct misc_dev_info*)
                        (st->sb + MAX_SB_SIZE + BM_SUPER_SIZE);
                sb->data_size = __cpu_to_le64(
                        misc->device_size - __le64_to_cpu(sb->data_offset));
-       } else if (strncmp(update, "revert-reshape", 14) == 0) {
+               break;
+       case UOPT_SPEC_REVERT_RESHAPE_NOBACKUP:
+       case UOPT_REVERT_RESHAPE:
                rv = -2;
                if (!(sb->feature_map &
                      __cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE)))
@@ -1476,7 +1501,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                         * If that couldn't happen, the "-nobackup" version
                         * will be used.
                         */
-                       if (strcmp(update, "revert-reshape-nobackup") == 0 &&
+                       if (update == UOPT_SPEC_REVERT_RESHAPE_NOBACKUP &&
                            sb->reshape_position == 0 &&
                            (__le32_to_cpu(sb->delta_disks) > 0 ||
                             (__le32_to_cpu(sb->delta_disks) == 0 &&
@@ -1500,8 +1525,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                         * So we reject a revert-reshape unless the
                         * alignment is good.
                         */
-                       if (__le32_to_cpu(sb->level) >= 4 &&
-                           __le32_to_cpu(sb->level) <= 6) {
+                       if (is_level456(__le32_to_cpu(sb->level))) {
                                reshape_sectors =
                                        __le64_to_cpu(sb->reshape_position);
                                reshape_chunk = __le32_to_cpu(sb->new_chunk);
@@ -1540,18 +1564,40 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                        }
                done:;
                }
-       } else if (strcmp(update, "_reshape_progress") == 0)
+               break;
+       case UOPT_SPEC__RESHAPE_PROGRESS:
                sb->reshape_position = __cpu_to_le64(info->reshape_progress);
-       else if (strcmp(update, "writemostly") == 0)
+               break;
+       case UOPT_SPEC_WRITEMOSTLY:
                sb->devflags |= WriteMostly1;
-       else if (strcmp(update, "readwrite") == 0)
+               break;
+       case UOPT_SPEC_READWRITE:
                sb->devflags &= ~WriteMostly1;
-       else if (strcmp(update, "failfast") == 0)
+               break;
+       case UOPT_SPEC_FAILFAST:
                sb->devflags |= FailFast1;
-       else if (strcmp(update, "nofailfast") == 0)
+               break;
+       case UOPT_SPEC_NOFAILFAST:
                sb->devflags &= ~FailFast1;
-       else
+               break;
+       case UOPT_LAYOUT_ORIGINAL:
+       case UOPT_LAYOUT_ALTERNATE:
+       case UOPT_LAYOUT_UNSPECIFIED:
+               if (__le32_to_cpu(sb->level) != 0) {
+                       pr_err("%s: %s only supported for RAID0\n",
+                              devname ?: "", map_num(update_options, update));
+                       rv = -1;
+               } else if (update == UOPT_LAYOUT_UNSPECIFIED) {
+                       sb->feature_map &= ~__cpu_to_le32(MD_FEATURE_RAID0_LAYOUT);
+                       sb->layout = 0;
+               } else {
+                       sb->feature_map |= __cpu_to_le32(MD_FEATURE_RAID0_LAYOUT);
+                       sb->layout = __cpu_to_le32(update == UOPT_LAYOUT_ORIGINAL ? 1 : 2);
+               }
+               break;
+       default:
                rv = -1;
+       }
 
        sb->sb_csum = calc_sb_1_csum(sb);
 
@@ -1567,7 +1613,7 @@ static int init_super1(struct supertype *st, mdu_array_info_t *info,
        char defname[10];
        int sbsize;
 
-       if (posix_memalign((void**)&sb, 4096, SUPER1_SIZE) != 0) {
+       if (posix_memalign((void **)&sb, 4096, SUPER1_SIZE) != 0) {
                pr_err("could not allocate superblock\n");
                return 0;
        }
@@ -1601,8 +1647,8 @@ static int init_super1(struct supertype *st, mdu_array_info_t *info,
                name = defname;
        }
        if (homehost &&
-           strchr(name, ':')== NULL &&
-           strlen(homehost)+1+strlen(name) < 32) {
+           strchr(name, ':') == NULL &&
+           strlen(homehost) + 1 + strlen(name) < 32) {
                strcpy(sb->set_name, homehost);
                strcat(sb->set_name, ":");
                strcat(sb->set_name, name);
@@ -1681,7 +1727,7 @@ static int add_to_super1(struct supertype *st, mdu_disk_info_t *dk,
 
        if (dk->number >= (int)__le32_to_cpu(sb->max_dev) &&
            __le32_to_cpu(sb->max_dev) < MAX_DEVS)
-               sb->max_dev = __cpu_to_le32(dk->number+1);
+               sb->max_dev = __cpu_to_le32(dk->number + 1);
 
        sb->dev_number = __cpu_to_le32(dk->number);
        sb->devflags = 0; /* don't copy another disks flags */
@@ -1695,7 +1741,10 @@ static int add_to_super1(struct supertype *st, mdu_disk_info_t *dk,
        di->devname = devname;
        di->disk = *dk;
        di->data_offset = data_offset;
-       get_dev_size(fd, NULL, &di->dev_size);
+
+       if (is_fd_valid(fd))
+               get_dev_size(fd, NULL, &di->dev_size);
+
        di->next = NULL;
        *dip = di;
 
@@ -1762,8 +1811,8 @@ static int store_super1(struct supertype *st, int fd)
                return 4;
 
        if (sb->feature_map & __cpu_to_le32(MD_FEATURE_BITMAP_OFFSET)) {
-               struct bitmap_super_s *bm = (struct bitmap_super_s*)
-                       (((char*)sb)+MAX_SB_SIZE);
+               struct bitmap_super_s *bm;
+               bm = (struct bitmap_super_s *)(((char *)sb) + MAX_SB_SIZE);
                if (__le32_to_cpu(bm->magic) == BITMAP_MAGIC) {
                        locate_bitmap1(st, fd, 0);
                        if (awrite(&afd, bm, sizeof(*bm)) != sizeof(*bm))
@@ -1850,7 +1899,7 @@ static int write_empty_r5l_meta_block(struct supertype *st, int fd)
 
        init_afd(&afd, fd);
 
-       if (posix_memalign((void**)&mb, 4096, META_BLOCK_SIZE) != 0) {
+       if (posix_memalign((void **)&mb, 4096, META_BLOCK_SIZE) != 0) {
                pr_err("Could not allocate memory for the meta block.\n");
                return 1;
        }
@@ -1886,6 +1935,14 @@ fail_to_write:
        return 1;
 }
 
+static bool has_raid0_layout(struct mdp_superblock_1 *sb)
+{
+       if (sb->level == 0 && sb->layout != 0)
+               return true;
+       else
+               return false;
+}
+
 static int write_init_super1(struct supertype *st)
 {
        struct mdp_superblock_1 *sb = st->sb;
@@ -1897,12 +1954,17 @@ static int write_init_super1(struct supertype *st)
        unsigned long long sb_offset;
        unsigned long long data_offset;
        long bm_offset;
-       int raid0_need_layout = 0;
+       bool raid0_need_layout = false;
+
+       /* Since linux kernel v5.4, raid0 always has a layout */
+       if (has_raid0_layout(sb) && get_linux_version() >= 5004000)
+               raid0_need_layout = true;
 
        for (di = st->info; di; di = di->next) {
                if (di->disk.state & (1 << MD_DISK_JOURNAL))
                        sb->feature_map |= __cpu_to_le32(MD_FEATURE_JOURNAL);
-               if (sb->level == 0 && sb->layout != 0) {
+               if (has_raid0_layout(sb) && !raid0_need_layout) {
+
                        struct devinfo *di2 = st->info;
                        unsigned long long s1, s2;
                        s1 = di->dev_size;
@@ -1914,7 +1976,7 @@ static int write_init_super1(struct supertype *st)
                                s2 -= di2->data_offset;
                        s2 /= __le32_to_cpu(sb->chunksize);
                        if (s1 != s2)
-                               raid0_need_layout = 1;
+                               raid0_need_layout = true;
                }
        }
 
@@ -1951,11 +2013,6 @@ static int write_init_super1(struct supertype *st)
                                /* same array, so preserve events and
                                 * dev_number */
                                sb->events = refsb->events;
-                               /* bugs in 2.6.17 and earlier mean the
-                                * dev_number chosen in Manage must be preserved
-                                */
-                               if (get_linux_version() >= 2006018)
-                                       sb->dev_number = refsb->dev_number;
                        }
                        free_super1(refst);
                }
@@ -2100,7 +2157,8 @@ out:
        return rv;
 }
 
-static int compare_super1(struct supertype *st, struct supertype *tst)
+static int compare_super1(struct supertype *st, struct supertype *tst,
+                         int verbose)
 {
        /*
         * return:
@@ -2118,7 +2176,7 @@ static int compare_super1(struct supertype *st, struct supertype *tst)
                return 1;
 
        if (!first) {
-               if (posix_memalign((void**)&first, 4096, SUPER1_SIZE) != 0) {
+               if (posix_memalign((void **)&first, 4096, SUPER1_SIZE) != 0) {
                        pr_err("could not allocate superblock\n");
                        return 1;
                }
@@ -2162,6 +2220,7 @@ static int load_super1(struct supertype *st, int fd, char *devname)
                tst.ss = &super1;
                for (tst.minor_version = 0; tst.minor_version <= 2;
                     tst.minor_version++) {
+                       tst.ignore_hw_compat = st->ignore_hw_compat;
                        switch(load_super1(&tst, fd, devname)) {
                        case 0: super = tst.sb;
                                if (bestvers == -1 ||
@@ -2230,7 +2289,7 @@ static int load_super1(struct supertype *st, int fd, char *devname)
                return 1;
        }
 
-       if (posix_memalign((void**)&super, 4096, SUPER1_SIZE) != 0) {
+       if (posix_memalign((void **)&super, 4096, SUPER1_SIZE) != 0) {
                pr_err("could not allocate superblock\n");
                return 1;
        }
@@ -2268,16 +2327,30 @@ static int load_super1(struct supertype *st, int fd, char *devname)
                free(super);
                return 2;
        }
-       st->sb = super;
 
-       bsb = (struct bitmap_super_s *)(((char*)super)+MAX_SB_SIZE);
+       bsb = (struct bitmap_super_s *)(((char *)super) + MAX_SB_SIZE);
 
        misc = (struct misc_dev_info*)
-         (((char*)super)+MAX_SB_SIZE+BM_SUPER_SIZE);
+               (((char *)super) + MAX_SB_SIZE+BM_SUPER_SIZE);
        misc->device_size = dsize;
        if (st->data_offset == INVALID_SECTORS)
                st->data_offset = __le64_to_cpu(super->data_offset);
 
+       if (st->minor_version >= 1 &&
+           st->ignore_hw_compat == 0 &&
+           ((role_from_sb(super) != MD_DISK_ROLE_JOURNAL &&
+             dsize < (__le64_to_cpu(super->data_offset) +
+                      __le64_to_cpu(super->size))) ||
+            dsize < (__le64_to_cpu(super->data_offset) +
+                     __le64_to_cpu(super->data_size)))) {
+               if (devname)
+                       pr_err("Device %s is not large enough for data described in superblock\n",
+                              devname);
+               free(super);
+               return 2;
+       }
+       st->sb = super;
+
        /* Now check on the bitmap superblock */
        if ((__le32_to_cpu(super->feature_map)&MD_FEATURE_BITMAP_OFFSET) == 0)
                return 0;
@@ -2296,8 +2369,8 @@ static int load_super1(struct supertype *st, int fd, char *devname)
        return 0;
 
  no_bitmap:
-       super->feature_map = __cpu_to_le32(__le32_to_cpu(super->feature_map)
-                                          ~MD_FEATURE_BITMAP_OFFSET);
+       super->feature_map = __cpu_to_le32(__le32_to_cpu(super->feature_map) &
+                                          ~MD_FEATURE_BITMAP_OFFSET);
        return 0;
 }
 
@@ -2355,7 +2428,7 @@ static __u64 avail_size1(struct supertype *st, __u64 devsize,
        if (__le32_to_cpu(super->feature_map) & MD_FEATURE_BITMAP_OFFSET) {
                /* hot-add. allow for actual size of bitmap */
                struct bitmap_super_s *bsb;
-               bsb = (struct bitmap_super_s *)(((char*)super)+MAX_SB_SIZE);
+               bsb = (struct bitmap_super_s *)(((char *)super) + MAX_SB_SIZE);
                bmspace = calc_bitmap_size(bsb, 4096) >> 9;
        } else if (md_feature_any_ppl_on(super->feature_map)) {
                bmspace = __le16_to_cpu(super->ppl.size);
@@ -2424,7 +2497,7 @@ add_internal_bitmap1(struct supertype *st,
        int creating = 0;
        int len;
        struct mdp_superblock_1 *sb = st->sb;
-       bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE);
+       bitmap_super_t *bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE);
        int uuid[4];
 
        if (__le64_to_cpu(sb->data_size) == 0)
@@ -2512,10 +2585,10 @@ add_internal_bitmap1(struct supertype *st,
        max_bits = (room * 512 - sizeof(bitmap_super_t)) * 8;
 
        min_chunk = 4096; /* sub-page chunks don't work yet.. */
-       bits = (size*512)/min_chunk +1;
+       bits = (size * 512) / min_chunk + 1;
        while (bits > max_bits) {
                min_chunk *= 2;
-               bits = (bits+1)/2;
+               bits = (bits + 1) / 2;
        }
        if (chunk == UnSet) {
                /* For practical purpose, 64Meg is a good
@@ -2533,8 +2606,8 @@ add_internal_bitmap1(struct supertype *st,
                /* start bitmap on a 4K boundary with enough space for
                 * the bitmap
                 */
-               bits = (size*512) / chunk + 1;
-               room = ((bits+7)/8 + sizeof(bitmap_super_t) +4095)/4096;
+               bits = (size * 512) / chunk + 1;
+               room = ((bits + 7) / 8 + sizeof(bitmap_super_t) + 4095) / 4096;
                room *= 8; /* convert 4K blocks to sectors */
                offset = -room - bbl_size;
        }
@@ -2568,8 +2641,9 @@ add_internal_bitmap1(struct supertype *st,
 
 static int locate_bitmap1(struct supertype *st, int fd, int node_num)
 {
-       unsigned long long offset;
+       unsigned long long offset, bm_sectors_per_node;
        struct mdp_superblock_1 *sb;
+       bitmap_super_t *bms;
        int mustfree = 0;
        int ret;
 
@@ -2584,8 +2658,13 @@ static int locate_bitmap1(struct supertype *st, int fd, int node_num)
                ret = 0;
        else
                ret = -1;
-       offset = __le64_to_cpu(sb->super_offset);
-       offset += (int32_t) __le32_to_cpu(sb->bitmap_offset) * (node_num + 1);
+
+       offset = __le64_to_cpu(sb->super_offset) + (int32_t)__le32_to_cpu(sb->bitmap_offset);
+       if (node_num) {
+               bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE);
+               bm_sectors_per_node = calc_bitmap_size(bms, 4096) >> 9;
+               offset += bm_sectors_per_node * node_num;
+       }
        if (mustfree)
                free(sb);
        lseek64(fd, offset<<9, 0);
@@ -2595,7 +2674,7 @@ static int locate_bitmap1(struct supertype *st, int fd, int node_num)
 static int write_bitmap1(struct supertype *st, int fd, enum bitmap_update update)
 {
        struct mdp_superblock_1 *sb = st->sb;
-       bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb)+MAX_SB_SIZE);
+       bitmap_super_t *bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE);
        int rv = 0;
        void *buf;
        int towrite, n, len;
@@ -2623,7 +2702,17 @@ static int write_bitmap1(struct supertype *st, int fd, enum bitmap_update update
                }
 
                if (bms->version == BITMAP_MAJOR_CLUSTERED) {
-                       if (__cpu_to_le32(st->nodes) < bms->nodes) {
+                       if (st->nodes == 1) {
+                               /* the parameter for nodes is not valid */
+                               pr_err("Warning: cluster-md at least needs two nodes\n");
+                               return -EINVAL;
+                       } else if (st->nodes == 0) {
+                               /*
+                                * parameter "--nodes" is not specified, (eg, add a disk to
+                                * clustered raid)
+                                */
+                               break;
+                       } else if (__cpu_to_le32(st->nodes) < bms->nodes) {
                                /*
                                 * Since the nodes num is not increased, no
                                 * need to check the space enough or not,
@@ -2669,7 +2758,10 @@ static int write_bitmap1(struct supertype *st, int fd, enum bitmap_update update
 
        init_afd(&afd, fd);
 
-       locate_bitmap1(st, fd, 0);
+       if (locate_bitmap1(st, fd, 0) < 0) {
+               pr_err("Error: Invalid bitmap\n");
+               return -EINVAL;
+       }
 
        if (posix_memalign(&buf, 4096, 4096))
                return -ENOMEM;
@@ -2743,9 +2835,10 @@ static int validate_geometry1(struct supertype *st, int level,
        unsigned long long ldsize, devsize;
        int bmspace;
        unsigned long long headroom;
+       unsigned long long overhead;
        int fd;
 
-       if (level == LEVEL_CONTAINER) {
+       if (is_container(level)) {
                if (verbose)
                        pr_err("1.x metadata does not support containers\n");
                return 0;
@@ -2775,10 +2868,6 @@ static int validate_geometry1(struct supertype *st, int level,
        close(fd);
 
        devsize = ldsize >> 9;
-       if (devsize < 24) {
-               *freesize = 0;
-               return 0;
-       }
 
        /* creating:  allow suitable space for bitmap or PPL */
        if (consistency_policy == CONSISTENCY_POLICY_PPL)
@@ -2819,15 +2908,27 @@ static int validate_geometry1(struct supertype *st, int level,
        case 0: /* metadata at end.  Round down and subtract space to reserve */
                devsize = (devsize & ~(4ULL*2-1));
                /* space for metadata, bblog, bitmap/ppl */
-               devsize -= 8*2 + 8 + bmspace;
+               overhead = 8*2 + 8 + bmspace;
+               if (devsize < overhead) /* detect underflow */
+                       goto dev_too_small_err;
+               devsize -= overhead;
                break;
        case 1:
        case 2:
+               if (devsize < data_offset) /* detect underflow */
+                       goto dev_too_small_err;
                devsize -= data_offset;
                break;
        }
        *freesize = devsize;
        return 1;
+
+/* Error condition, device cannot even hold the overhead. */
+dev_too_small_err:
+       fprintf(stderr, "device %s is too small (%lluK) for "
+                       "required metadata!\n", subdev, devsize>>1);
+       *freesize = 0;
+       return 0;
 }
 
 void *super1_make_v0(struct supertype *st, struct mdinfo *info, mdp_super_t *sb0)
@@ -2847,16 +2948,16 @@ void *super1_make_v0(struct supertype *st, struct mdinfo *info, mdp_super_t *sb0
 
        copy_uuid(sb->set_uuid, info->uuid, super1.swapuuid);
        sprintf(sb->set_name, "%d", sb0->md_minor);
-       sb->ctime = __cpu_to_le32(info->array.ctime+1);
+       sb->ctime = __cpu_to_le32(info->array.ctime + 1);
        sb->level = __cpu_to_le32(info->array.level);
        sb->layout = __cpu_to_le32(info->array.layout);
        sb->size = __cpu_to_le64(info->component_size);
-       sb->chunksize = __cpu_to_le32(info->array.chunk_size/512);
+       sb->chunksize = __cpu_to_le32(info->array.chunk_size / 512);
        sb->raid_disks = __cpu_to_le32(info->array.raid_disks);
        if (info->array.level > 0)
                sb->data_size = sb->size;
        else
-               sb->data_size = st->ss->avail_size(st, st->devsize/512, 0);
+               sb->data_size = st->ss->avail_size(st, st->devsize / 512, 0);
        sb->resync_offset = MaxSector;
        sb->max_dev = __cpu_to_le32(MD_SB_DISKS);
        sb->dev_number = __cpu_to_le32(info->disk.number);