]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Fix assembling of raid10 in the face of missing devices. stable-1
authorNeil Brown <neilb@suse.de>
Mon, 5 Sep 2005 01:14:26 +0000 (01:14 +0000)
committerNeil Brown <neilb@suse.de>
Mon, 5 Sep 2005 01:14:26 +0000 (01:14 +0000)
We now check if enough devices are present properly, so
--force can be used to good effect.

Signed-off-by: Neil Brown <neilb@suse.de>
Assemble.c
mdadm.h
util.c

index ace5717c310adb7dc932b21dd30bc67756025df9..49639cdbfd7027c36d03d91832a304ec074178e0 100644 (file)
@@ -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 f4a8d20c6c3cd752c6a3f6eeed32ed8994e733a0..8f0c32e80749934ab97c021f7af149feeb8b9cf7 100644 (file)
--- 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 5bac0ec4003ed6123931378d64c18163df716f41..e94edc845e81cffd9157ad95c2047e7b725d5bc3 100644 (file)
--- 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;