X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=blobdiff_plain;f=super1.c;h=e0d80be1e5dfa22e3358b5bd1274e85719f08938;hp=cedbb53b4f2ef8dbe6a7aa5aee3ba01a3a645990;hb=HEAD;hpb=329dfc28debb58ffe7bd1967cea00fc583139aca diff --git a/super1.c b/super1.c index cedbb53b..81d29a65 100644 --- 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; imax_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<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);