]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Grow: warn if growing an array will make it degraded.
authorNeilBrown <neilb@suse.de>
Thu, 9 Dec 2010 00:51:13 +0000 (11:51 +1100)
committerNeilBrown <neilb@suse.de>
Thu, 9 Dec 2010 00:51:13 +0000 (11:51 +1100)
Growing an array when there aren't enough spares can make the array
degraded.  This works but might not be what is wanted.
So warn the user in this case and require a --force to go ahead
with the reshape.

Signed-off-by: NeilBrown <neilb@suse.de>
Grow.c
mdadm.c
mdadm.h

diff --git a/Grow.c b/Grow.c
index cf09a604122482e14d983320dc2c487faac0dee1..222d755c81d387de82339a6adc95bf7c67daafa6 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -996,7 +996,8 @@ unsigned long compute_backup_blocks(int nchunk, int ochunk,
 
 int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                 long long size,
-                int level, char *layout_str, int chunksize, int raid_disks)
+                int level, char *layout_str, int chunksize, int raid_disks,
+                int force)
 {
        /* Make some changes in the shape of an array.
         * The kernel must support the change.
@@ -1128,6 +1129,19 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
 
                if (mdmon_running(container_dev))
                        st->update_tail = &st->updates;
+       } 
+
+       if (raid_disks > array.raid_disks &&
+           array.spare_disks < (raid_disks - array.raid_disks) &&
+           !force) {
+               fprintf(stderr,
+                       Name ": Need %d spare%s to avoid degraded array,"
+                       " and only have %d.\n"
+                       "       Use --force to over-ride this check.\n",
+                       raid_disks - array.raid_disks, 
+                       raid_disks - array.raid_disks == 1 ? "" : "s", 
+                       array.spare_disks);
+               return 1;
        }
 
        sra = sysfs_read(fd, 0, GET_LEVEL | GET_DISKS | GET_DEVS | GET_STATE);
@@ -1309,6 +1323,36 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                                rv = 1;/* not possible */
                                goto release;
                        }
+                       if (!force) {
+                               /* Need to check there are enough spares */
+                               int spares_needed = 0;
+                               switch (array.level * 16 + level) {
+                               case 0x05:
+                                       spares_needed = 1; break;
+                               case 0x06:
+                                       spares_needed = 2; break;
+                               case 0x15:
+                                       spares_needed = 1; break;
+                               case 0x16:
+                                       spares_needed = 2; break;
+                               case 0x56:
+                                       spares_needed = 1; break;
+                               }
+                               if (raid_disks > array.raid_disks)
+                                       spares_needed += raid_disks-array.raid_disks;
+                               if (spares_needed > array.spare_disks) {
+                                       fprintf(stderr,
+                                               Name ": Need %d spare%s to avoid"
+                                               " degraded array, and only have %d.\n"
+                                               "       Use --force to over-ride"
+                                               " this check.\n",
+                                               spares_needed,
+                                               spares_needed == 1 ? "" : "s", 
+                                               array.spare_disks);
+                                       rv = 1;
+                                       goto release;
+                               }
+                       }
                        err = sysfs_set_str(sra, NULL, "level", c);
                        if (err) {
                                err = errno;
diff --git a/mdadm.c b/mdadm.c
index 187ad891031de6b80f3933c1528d312c1d0c7ecc..dd5311d5912c7a503452b33f36aaf8d6cc70ee9e 100644 (file)
--- a/mdadm.c
+++ b/mdadm.c
@@ -1610,7 +1610,8 @@ int main(int argc, char *argv[])
                } else if (size >= 0 || raiddisks != 0 || layout_str != NULL
                           || chunk != 0 || level != UnSet) {
                        rv = Grow_reshape(devlist->devname, mdfd, quiet, backup_file,
-                                         size, level, layout_str, chunk, raiddisks);
+                                         size, level, layout_str, chunk, raiddisks,
+                                         force);
                } else if (array_size < 0)
                        fprintf(stderr, Name ": no changes to --grow\n");
                break;
diff --git a/mdadm.h b/mdadm.h
index 175d228bf85bec53a9dc2537ad485485259ef752..8e2c23146c33c7c6864a9e04a3defb319ae5d702 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -965,7 +965,8 @@ extern int Grow_Add_device(char *devname, int fd, char *newdev);
 extern int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int write_behind, int force);
 extern int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                        long long size,
-                       int level, char *layout_str, int chunksize, int raid_disks);
+                       int level, char *layout_str, int chunksize, int raid_disks,
+                       int force);
 extern int Grow_restart(struct supertype *st, struct mdinfo *info,
                        int *fdlist, int cnt, char *backup_file, int verbose);
 extern int Grow_continue(int mdfd, struct supertype *st,