]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Grow.c
FIX: delta_disk can have UnSet value
[thirdparty/mdadm.git] / Grow.c
diff --git a/Grow.c b/Grow.c
index 2a1383188aa5a47216a90d7eaf9a321124cc6ee8..9ae2ecd281ab4a0fbac4fd72aba1bdfb1ef79381 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -565,7 +565,8 @@ static void wait_reshape(struct mdinfo *sra)
 
 static int reshape_super(struct supertype *st, long long size, int level,
                         int layout, int chunksize, int raid_disks,
-                        char *backup_file, char *dev, int verbose)
+                        int delta_disks, char *backup_file, char *dev,
+                        int verbose)
 {
        /* nothing extra to check in the native case */
        if (!st->ss->external)
@@ -578,7 +579,8 @@ static int reshape_super(struct supertype *st, long long size, int level,
        }
 
        return st->ss->reshape_super(st, size, level, layout, chunksize,
-                                    raid_disks, backup_file, dev, verbose);
+                                    raid_disks, delta_disks, backup_file, dev,
+                                    verbose);
 }
 
 static void sync_metadata(struct supertype *st)
@@ -832,7 +834,7 @@ int reshape_open_backup_file(char *backup_file,
        }
 
        memset(buf, 0, 512);
-       for (i=0; i < blocks + 1 ; i++) {
+       for (i=0; i < blocks + 8 ; i++) {
                if (write(*fdlist, buf, 512) != 512) {
                        fprintf(stderr, Name ": %s: cannot create"
                                " backup file %s: %s\n",
@@ -1416,7 +1418,8 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
        if (size >= 0 && (size == 0 || size != array.size)) {
                long long orig_size = array.size;
 
-               if (reshape_super(st, size, UnSet, UnSet, 0, 0, NULL, devname, !quiet)) {
+               if (reshape_super(st, size, UnSet, UnSet, 0, 0, UnSet, NULL,
+                                 devname, !quiet)) {
                        rv = 1;
                        goto release;
                }
@@ -1438,7 +1441,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
 
                        /* restore metadata */
                        if (reshape_super(st, orig_size, UnSet, UnSet, 0, 0,
-                                         NULL, devname, !quiet) == 0)
+                                         UnSet, NULL, devname, !quiet) == 0)
                                sync_metadata(st);
                        fprintf(stderr, Name ": Cannot set device size for %s: %s\n",
                                devname, strerror(err));
@@ -1575,7 +1578,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
 
                if (reshape_super(st, info.component_size, info.new_level,
                                  info.new_layout, info.new_chunk,
-                                 info.array.raid_disks + info.delta_disks,
+                                 info.array.raid_disks, info.delta_disks,
                                  backup_file, devname, quiet)) {
                        rv = 1;
                        goto release;
@@ -1677,6 +1680,7 @@ static int reshape_array(char *container, int fd, char *devname,
                        fprintf(stderr, Name ": level of %s changed to %s\n",
                                devname, c);    
                orig_level = info->array.level;
+               sysfs_freeze_array(info);
 
                if (reshape.level > 0 && st->ss->external) {
                        /* make sure mdmon is aware of the new level */
@@ -1838,7 +1842,9 @@ started:
 
        /* Now we need to open all these devices so we can read/write.
         */
-       nrdisks = array.raid_disks + sra->array.spare_disks;
+       nrdisks = max(reshape.before.data_disks,
+                     reshape.after.data_disks) + reshape.parity
+               + sra->array.spare_disks;
        fdlist = malloc((1+nrdisks) * sizeof(int));
        offsets = malloc((1+nrdisks) * sizeof(offsets[0]));
        if (!fdlist || !offsets) {
@@ -1846,7 +1852,8 @@ started:
                goto release;
        }
 
-       d = reshape_prepare_fdlist(devname, sra, array.raid_disks,
+       odisks = reshape.before.data_disks + reshape.parity;
+       d = reshape_prepare_fdlist(devname, sra, odisks,
                                   nrdisks, blocks, backup_file,
                                   fdlist, offsets);
        if (d < 0) {
@@ -1998,8 +2005,6 @@ started:
                fd = -1;
        mlockall(MCL_FUTURE);
 
-       odisks = reshape.before.data_disks + reshape.parity;
-
        if (st->ss->external) {
                /* metadata handler takes it from here */
                done = st->ss->manage_reshape(
@@ -2093,6 +2098,7 @@ started:
 out:
        if (forked)
                return 0;
+       unfreeze(st);
        exit(0);
 
 release:
@@ -2120,9 +2126,11 @@ int reshape_container(char *container, int cfd, char *devname,
         */
        if (reshape_super(st, -1, info->new_level,
                          info->new_layout, info->new_chunk,
-                         info->array.raid_disks + info->delta_disks,
-                         backup_file, devname, quiet))
+                         info->array.raid_disks, info->delta_disks,
+                         backup_file, devname, quiet)) {
+               unfreeze(st);
                return 1;
+       }
 
        sync_metadata(st);
 
@@ -2133,6 +2141,7 @@ int reshape_container(char *container, int cfd, char *devname,
        switch (fork()) {
        case -1: /* error */
                perror("Cannot fork to complete reshape\n");
+               unfreeze(st);
                return 1;
        default: /* parent */
                printf(Name ": multi-array reshape continues in background\n");
@@ -2429,6 +2438,9 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape,
        /* Round to chunk size as some kernels give an erroneously high number */
        max_progress /= info->new_chunk/512;
        max_progress *= info->new_chunk/512;
+       /* And round to old chunk size as the kernel wants that */
+       max_progress /= info->array.chunk_size/512;
+       max_progress *= info->array.chunk_size/512;
        /* Limit progress to the whole device */
        if (max_progress > info->component_size)
                max_progress = info->component_size;
@@ -2941,6 +2953,8 @@ int child_monitor(int afd, struct mdinfo *sra, struct reshape *reshape,
                                if (offset < suspend_point/data)
                                        break;
                        }
+                       if (actual_stripes == 0)
+                               break;
                        grow_backup(sra, offset, actual_stripes,
                                    fds, offsets,
                                    disks, chunk, level, layout,