From 6e6dc574d60f108fdc49f3b755d9baeec1335ba2 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Mon, 5 Sep 2005 01:14:26 +0000 Subject: 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 --- Assemble.c | 17 ++++++++++++----- mdadm.h | 3 ++- util.c | 25 +++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/Assemble.c b/Assemble.c index ace5717..49639cd 100644 --- a/Assemble.c +++ b/Assemble.c @@ -119,6 +119,7 @@ int Assemble(char *mddev, int mdfd, int start_partial_ok = force || devlist==NULL; unsigned int num_devs; mddev_dev_t tmpdev; + char *avail; vers = md_get_version(mdfd); if (vers <= 0) { @@ -389,6 +390,8 @@ int Assemble(char *mddev, int mdfd, /* now we have some devices that might be suitable. * I wonder how many */ + avail = malloc(first_super.raid_disks); + memset(avail, 0, first_super.raid_disks); okcnt = 0; sparecnt=0; for (i=0; i< bestcnt ;i++) { @@ -407,13 +410,16 @@ int Assemble(char *mddev, int mdfd, if (devices[j].events+event_margin >= devices[most_recent].events) { devices[j].uptodate = 1; - if (i < first_super.raid_disks) + if (i < first_super.raid_disks) { okcnt++; - else + avail[i]=1; + } else sparecnt++; } } - while (force && !enough(first_super.level, first_super.raid_disks, okcnt)) { + while (force && !enough(first_super.level, first_super.raid_disks, + first_super.layout, + avail, okcnt)) { /* Choose the newest best drive which is * not up-to-date, update the superblock * and add it. @@ -466,6 +472,7 @@ int Assemble(char *mddev, int mdfd, close(fd); devices[chosen_drive].events = devices[most_recent].events; devices[chosen_drive].uptodate = 1; + avail[chosen_drive] = 1; okcnt++; } @@ -624,7 +631,7 @@ This doesnt work yet if (runstop == 1 || (runstop == 0 && - ( enough(first_super.level, first_super.raid_disks, okcnt) && + ( enough(first_super.level, first_super.raid_disks, first_super.layout, avail, okcnt) && (okcnt >= req_cnt || start_partial_ok) ))) { if (ioctl(mdfd, RUN_ARRAY, NULL)==0) { @@ -649,7 +656,7 @@ This doesnt work yet 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(first_super.level, first_super.raid_disks, okcnt)) + if (!enough(first_super.level, first_super.raid_disks, first_super.layout, avail, okcnt)) fprintf(stderr, " - not enough to start the array.\n"); else { if (req_cnt == first_super.raid_disks) diff --git a/mdadm.h b/mdadm.h index f4a8d20..8f0c32e 100644 --- a/mdadm.h +++ b/mdadm.h @@ -231,7 +231,8 @@ extern int same_uuid(int a[4], int b[4]); extern int compare_super(mdp_super_t *first, mdp_super_t *second); extern unsigned long calc_sb_csum(mdp_super_t *super); extern int store_super(int fd, mdp_super_t *super); -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 --git a/util.c b/util.c index 5bac0ec..e94edc8 100644 --- a/util.c +++ b/util.c @@ -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; -- cgit