Status: ok Fix assembling of raid10 in the face of missing devices. We now check if enough devices are present properly, so --force can be used to good effect. Signed-off-by: Neil Brown ### Diffstat output ./Assemble.c | 17 ++++++++++++----- ./mdadm.h | 3 ++- ./super0.c | 5 +++++ ./super1.c | 6 ++++++ ./util.c | 25 +++++++++++++++++++++++-- 5 files changed, 48 insertions(+), 8 deletions(-) diff ./Assemble.c~current~ ./Assemble.c --- ./Assemble.c~current~ 2005-09-05 10:54:48.000000000 +1000 +++ ./Assemble.c 2005-09-05 10:55:01.000000000 +1000 @@ -118,6 +118,7 @@ int Assemble(struct supertype *st, char mddev_dev_t tmpdev; struct mdinfo info; struct mddev_ident_s ident2; + char *avail; vers = md_get_version(mdfd); if (vers <= 0) { @@ -359,6 +360,8 @@ int Assemble(struct supertype *st, char /* now we have some devices that might be suitable. * I wonder how many */ + avail = malloc(info.array.raid_disks); + memset(avail, 0, info.array.raid_disks); okcnt = 0; sparecnt=0; for (i=0; i< bestcnt ;i++) { @@ -377,13 +380,16 @@ int Assemble(struct supertype *st, char if (devices[j].events+event_margin >= devices[most_recent].events) { devices[j].uptodate = 1; - if (i < info.array.raid_disks) + if (i < info.array.raid_disks) { okcnt++; - else + avail[i]=1; + } else sparecnt++; } } - while (force && !enough(info.array.level, info.array.raid_disks, okcnt)) { + while (force && !enough(info.array.level, info.array.raid_disks, + info.array.layout, + avail, okcnt)) { /* Choose the newest best drive which is * not up-to-date, update the superblock * and add it. @@ -434,6 +440,7 @@ int Assemble(struct supertype *st, char close(fd); devices[chosen_drive].events = devices[most_recent].events; devices[chosen_drive].uptodate = 1; + avail[chosen_drive] = 1; okcnt++; free(super); } @@ -599,7 +606,7 @@ int Assemble(struct supertype *st, char if (runstop == 1 || (runstop == 0 && - ( enough(info.array.level, info.array.raid_disks, okcnt) && + ( enough(info.array.level, info.array.raid_disks, info.array.layout, avail, okcnt) && (okcnt >= req_cnt || start_partial_ok) ))) { if (ioctl(mdfd, RUN_ARRAY, NULL)==0) { @@ -627,7 +634,7 @@ int Assemble(struct supertype *st, char fprintf(stderr, Name ": %s assembled from %d drive%s", mddev, okcnt, okcnt==1?"":"s"); if (sparecnt) fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s"); - if (!enough(info.array.level, info.array.raid_disks, okcnt)) + if (!enough(info.array.level, info.array.raid_disks, info.array.layout, avail, okcnt)) fprintf(stderr, " - not enough to start the array.\n"); else { if (req_cnt == info.array.raid_disks) diff ./mdadm.h~current~ ./mdadm.h --- ./mdadm.h~current~ 2005-09-05 10:54:51.000000000 +1000 +++ ./mdadm.h 2005-09-05 10:55:01.000000000 +1000 @@ -291,7 +291,8 @@ extern void uuid_from_super(int uuid[4], extern int same_uuid(int a[4], int b[4], int swapuuid); /* extern int compare_super(mdp_super_t *first, mdp_super_t *second);*/ extern unsigned long calc_csum(void *super, int bytes); -extern int enough(int level, int raid_disks, int avail_disks); +extern int enough(int level, int raid_disks, int layout, + char *avail, int avail_disks); extern int ask(char *mesg); diff ./super0.c~current~ ./super0.c --- ./super0.c~current~ 2005-09-05 10:54:51.000000000 +1000 +++ ./super0.c 2005-09-05 10:55:01.000000000 +1000 @@ -131,6 +131,10 @@ static void examine_super0(void *sbv) c = map_num(r5layout, sb->layout); printf(" Layout : %s\n", c?c:"-unknown-"); } + if (sb->level == 10) { + printf(" Layout : near=%d, far=%d\n", + sb->layout&255, (sb->layout>>8)&255); + } switch(sb->level) { case 0: case 4: @@ -234,6 +238,7 @@ static void getinfo_super0(struct mdinfo info->array.patch_version = sb->patch_version; info->array.raid_disks = sb->raid_disks; info->array.level = sb->level; + info->array.layout = sb->layout; info->array.md_minor = sb->md_minor; info->array.ctime = sb->ctime; diff ./super1.c~current~ ./super1.c --- ./super1.c~current~ 2005-09-05 10:54:51.000000000 +1000 +++ ./super1.c 2005-09-05 10:55:01.000000000 +1000 @@ -180,6 +180,11 @@ static void examine_super1(void *sbv) c = map_num(r5layout, __le32_to_cpu(sb->layout)); printf(" Layout : %s\n", c?c:"-unknown-"); } + if (__le32_to_cpu(sb->level) == 10) { + int lo = __le32_to_cpu(sb->layout); + printf(" Layout : near=%d, far=%d\n", + lo&255, (lo>>8)&255); + } switch(__le32_to_cpu(sb->level)) { case 0: case 4: @@ -290,6 +295,7 @@ static void getinfo_super1(struct mdinfo info->array.patch_version = 0; info->array.raid_disks = __le32_to_cpu(sb->raid_disks); info->array.level = __le32_to_cpu(sb->level); + info->array.layout = __le32_to_cpu(sb->layout); info->array.md_minor = -1; info->array.ctime = __le64_to_cpu(sb->ctime); diff ./util.c~current~ ./util.c --- ./util.c~current~ 2005-09-05 10:54:48.000000000 +1000 +++ ./util.c 2005-09-05 10:55:01.000000000 +1000 @@ -118,10 +118,31 @@ int get_linux_version() return (a*1000000)+(b*1000)+c; } -int enough(int level, int raid_disks, int avail_disks) +int enough(int level, int raid_disks, int layout, + char *avail, int avail_disks) { + int copies, first; switch (level) { - case 10: return 1; /* a lie, but it is hard to tell */ + case 10: + /* This is the tricky one - we need to check + * which actual disks are present. + */ + copies = (layout&255)* (layout>>8); + first=0; + do { + /* there must be one of the 'copies' form 'first' */ + int n = copies; + int cnt=0; + while (n--) { + if (avail[first]) + cnt++; + first = (first+1) % raid_disks; + } + if (cnt == 0) + return 0; + + } while (first != 0); + return 1; case -4: return avail_disks>= 1;