Give useful message if raid4/5/6 cannot be started because it is not clean and is...
authorNeil Brown <neilb@suse.de>
Thu, 14 Dec 2006 06:31:13 +0000 (17:31 +1100)
committerNeil Brown <neilb@suse.de>
Thu, 14 Dec 2006 06:31:13 +0000 (17:31 +1100)
Assemble.c
ChangeLog
mdadm.h
super0.c
super1.c
util.c

index 23e3583..59f4239 100644 (file)
@@ -111,6 +111,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
         *    START_ARRAY
         *
         */
+       int clean = 0;
        int must_close = 0;
        int old_linux = 0;
        int vers = 0; /* Keep gcc quite - it really is initialised */
@@ -583,6 +584,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
        }
 
        st->ss->getinfo_super(&info, first_super);
+       clean = info.array.state & 1;
 
        /* now we have some devices that might be suitable.
         * I wonder how many
@@ -617,7 +619,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                }
        }
        while (force && !enough(info.array.level, info.array.raid_disks,
-                               info.array.layout,
+                               info.array.layout, 1,
                                avail, okcnt)) {
                /* Choose the newest best drive which is
                 * not up-to-date, update the superblock
@@ -758,6 +760,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                change += st->ss->update_super(&info, super, "force-array",
                                        devices[chosen_drive].devname, verbose,
                                               0, NULL);
+               clean = 1;
        }
 
        if (change) {
@@ -894,7 +897,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                
                if (runstop == 1 ||
                    (runstop <= 0 &&
-                    ( enough(info.array.level, info.array.raid_disks, info.array.layout, avail, okcnt) &&
+                    ( enough(info.array.level, info.array.raid_disks,
+                             info.array.layout, clean, avail, okcnt) &&
                       (okcnt >= req_cnt || start_partial_ok)
                             ))) {
                        if (ioctl(mdfd, RUN_ARRAY, NULL)==0) {
@@ -937,6 +941,19 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        }
                        fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n",
                                mddev, strerror(errno));
+
+                       if (!enough(info.array.level, info.array.raid_disks,
+                                   info.array.layout, 1, avail, okcnt))
+                               fprintf(stderr, Name ": Not enough devices to "
+                                       "start the array.\n");
+                       else if (!enough(info.array.level,
+                                        info.array.raid_disks,
+                                        info.array.layout, clean,
+                                        avail, okcnt))
+                               fprintf(stderr, Name ": Not enough devices to "
+                                       "start the array while not clean "
+                                       "- consider --force.\n");
+
                        if (must_close) close(mdfd);
                        return 1;
                }
@@ -953,8 +970,16 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        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, info.array.layout, avail, okcnt))
+                       if (!enough(info.array.level, info.array.raid_disks,
+                                   info.array.layout, 1, avail, okcnt))
                                fprintf(stderr, " - not enough to start the array.\n");
+                       else if (!enough(info.array.level,
+                                        info.array.raid_disks,
+                                        info.array.layout, clean,
+                                        avail, okcnt))
+                               fprintf(stderr, " - not enough to start the "
+                                       "array while not clean - consider "
+                                       "--force.\n");
                        else {
                                if (req_cnt == info.array.raid_disks)
                                        fprintf(stderr, " - need all %d to start it", req_cnt);
index 46af0ee..756ed92 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,6 +10,8 @@ Changes Prior to this release
        can change size.
     -   Default to --auto=yes so the array devices with 'standard' names
        get created automatically, as this is almost always what is wanted.
+    -   Give useful message if raid4/5/6 cannot be started because it is
+       not clean and is also degraded.
 
 Changes Prior to 2.5.6 release
     -   Fix bug which meant "bitmap=xxx" in mdadm.conf was not handled
diff --git a/mdadm.h b/mdadm.h
index f6e7b5e..1976dd1 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -456,7 +456,7 @@ extern void uuid_from_super(int uuid[4], mdp_super_t *super);
 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 layout,
+extern int enough(int level, int raid_disks, int layout, int clean,
                   char *avail, int avail_disks);
 extern int ask(char *mesg);
 extern unsigned long long get_component_size(int fd);
index fbb7eb9..d2338a9 100644 (file)
--- a/super0.c
+++ b/super0.c
@@ -320,6 +320,7 @@ static void getinfo_super0(struct mdinfo *info, void *sbv)
        info->array.ctime = sb->ctime;
        info->array.utime = sb->utime;
        info->array.chunk_size = sb->chunk_size;
+       info->array.state = sb->state;
        info->component_size = sb->size*2;
 
        info->disk.state = sb->this_disk.state;
index 140f637..1890949 100644 (file)
--- a/super1.c
+++ b/super1.c
@@ -429,6 +429,7 @@ static void getinfo_super1(struct mdinfo *info, void *sbv)
        info->array.ctime = __le64_to_cpu(sb->ctime);
        info->array.utime = __le64_to_cpu(sb->utime);
        info->array.chunk_size = __le32_to_cpu(sb->chunksize)*512;
+       info->array.state = (__le64_to_cpu(sb->resync_offset)+1) ? 0 : 1;
 
        info->data_offset = __le64_to_cpu(sb->data_offset);
        info->component_size = __le64_to_cpu(sb->size);
diff --git a/util.c b/util.c
index 8d06848..6148ff8 100644 (file)
--- a/util.c
+++ b/util.c
@@ -170,7 +170,7 @@ void remove_partitions(int fd)
 #endif
 }
 
-int enough(int level, int raid_disks, int layout,
+int enough(int level, int raid_disks, int layout, int clean,
           char *avail, int avail_disks)
 {
        int copies, first;
@@ -205,9 +205,15 @@ int enough(int level, int raid_disks, int layout,
                return avail_disks >= 1;
        case 4:
        case 5:
-               return avail_disks >= raid_disks-1;
+               if (clean)
+                       return avail_disks >= raid_disks-1;
+               else
+                       return avail_disks >= raid_disks;
        case 6:
-               return avail_disks >= raid_disks-2;
+               if (clean)
+                       return avail_disks >= raid_disks-2;
+               else
+                       return avail_disks >= raid_disks;
        default:
                return 0;
        }